Compare commits

...

171 Commits

Author SHA1 Message Date
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
fa55fce76e Merge branch 'feature/119-Certificate_generation' of git.odit.services:lfk/frontend into feature/119-Certificate_generation 2021-04-03 19:59:20 +02:00
f47d5e347d Copy-paste fix
ref #119
2021-04-03 19:59:18 +02:00
7488a8b597 Copy-paste fix
ref #119
2021-04-03 19:58:24 +02:00
2e3ac154be Implemented generation for orgs
ref #119
2021-04-03 19:52:41 +02:00
2472640755 Implemented generation for teams
ref #119
2021-04-03 19:51:01 +02:00
7b685d6cad Added certificate generation from runner overview and detail
ref #119
2021-04-03 19:48:31 +02:00
17f6f4e616 Added i18n
ref #119
2021-04-03 19:46:17 +02:00
48cfc15cfb Removed useless console log
ref #119
2021-04-03 19:44:57 +02:00
bb9b779cee You can now generate certificates from the runner overview
ref #119
2021-04-03 19:44:26 +02:00
af63ce67ae Added basic certificate generation component
ref #119
2021-04-03 19:38:54 +02:00
5cc4871ec4 new license file version [CI SKIP] 2021-04-03 17:18:28 +00:00
c8cfe669b8 Merge pull request 'feature/108_vite_migration' (#118) from feature/108_vite_migration into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #118
close #108
2021-04-03 17:17:23 +00:00
8b74d6d759 bump @odit/lfk-client-js@0.10.1
ref #108
2021-04-03 19:16:53 +02:00
a9227768de 🐞 fix await for esNext
ref #108
2021-04-03 19:13:05 +02:00
d966e1d4de Merge branch 'dev' into feature/108_vite_migration
# Conflicts:
#	index.html
#	package.json
#	public/licenses.json
#	src/App.svelte
#	src/components/orgs/OrgOverview.svelte
#	src/components/teams/TeamsOverview.svelte
2021-04-03 19:10:10 +02:00
ceb2146c1b 🔨 dev container open
ref #108
2021-04-03 18:31:03 +02:00
8d006d8c74 version bump: vite-plugin-windicss@0.12.2
ref #108
2021-04-03 18:22:00 +02:00
777304f259 🔨🔥 alpine based devcontainer with working yarn PnP
ref #108
2021-04-02 21:57:56 +02:00
12433f7c23 🧹 reorder + fix package
ref #108
2021-04-02 21:56:57 +02:00
44b53da345 🚚 move @svitejs/vite-plugin-svelte to @sveltejs/vite-plugin-svelte
ref #108
2021-04-02 21:47:43 +02:00
ab45fc144e upgrade vite-plugin-windicss@0.12.1
ref #108
2021-04-02 21:20:48 +02:00
e99e9e0708 update licenses.json
ref #108
2021-04-02 21:20:05 +02:00
467404bfc8 🐞 fix main.js linking
ref #108
2021-04-02 21:19:49 +02:00
ce50fa2a62 🧹 drop unused dependencies
ref #108
2021-04-02 21:19:29 +02:00
10a011d842 🐞 fix vite config for production system
ref #108
2021-04-02 21:07:16 +02:00
5352410d0c 🐞 fix NGINX config
ref #108
2021-04-02 21:06:57 +02:00
c5d155396a 💾 prevent env.js from being cached
ref #108
2021-04-01 19:35:27 +02:00
93187099d3 🔨 re-added VS Code devcontainer config
ref #108
2021-04-01 19:35:10 +02:00
aa24b1dce5 📃 added readme
ref #108
2021-04-01 19:32:10 +02:00
eb3ede9593 fix dev script
ref #108
2021-04-01 19:30:31 +02:00
d7fecfbd0b version bumps
ref #108
2021-04-01 19:30:15 +02:00
b065b4ff21 📍 version bump + pin
ref #108
2021-03-30 18:36:20 +02:00
87370d24be Merge branch 'dev' of git.odit.services:lfk/frontend into dev
All checks were successful
continuous-integration/drone/push Build is passing
2021-03-30 18:29:03 +02:00
8f8b9988ad new license file version [CI SKIP] 2021-03-30 16:29:19 +00:00
f8ccf4f5d8 🚀RELEASE v0.11.0 2021-03-30 18:28:53 +02:00
25d8b86efd Merge pull request 'Generate and print bulk blank cards feature/116-download_blanc_cards' (#117) from feature/116-download_blanc_cards into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #117
2021-03-30 16:27:48 +00:00
0cd3e937d8 bump vite to 2.1.3
ref #108
2021-03-30 18:21:18 +02:00
89bb9c215e Sorted translations
ref #116
2021-03-29 18:52:25 +02:00
2d18686ce7 Bumped lfk client js version
ref #116
2021-03-29 18:52:10 +02:00
1d999d4910 Now returning cards on creation with pdf
ref #116
2021-03-29 18:23:17 +02:00
7dfaa7579a Bumped lfk-client-js
ref #116
2021-03-29 18:15:00 +02:00
08cb079e97 Fixed button styling
ref #116
2021-03-29 17:57:34 +02:00
450aa83592 Merge branch 'feature/116-download_blanc_cards' of git.odit.services:lfk/frontend into feature/116-download_blanc_cards
# Conflicts:
#	src/components/cards/AddCardBulkModal.svelte
2021-03-29 17:47:18 +02:00
0614c76e92 Added button (including translations
ref #116
2021-03-29 17:46:56 +02:00
97e338f9d4 Added button (including translations
ref #116
2021-03-29 17:46:51 +02:00
636f018daa Added comment
ref #116
2021-03-29 17:44:59 +02:00
c8d639024a Added function for generating cards with pdf
ref #116
2021-03-29 17:44:30 +02:00
6be2ee626a package cleanup 2021-03-26 21:22:46 +01:00
f7fc1967a5 🚀RELEASE v0.10.0
All checks were successful
continuous-integration/drone/push Build is passing
2021-03-26 20:07:14 +01:00
aedb8a765b new license file version [CI SKIP] 2021-03-26 19:06:59 +00:00
cf58bd15c3 Bumped lfk-client version 🔝
All checks were successful
continuous-integration/drone/push Build is passing
2021-03-26 20:05:26 +01:00
34f4f68524 new license file version [CI SKIP] 2021-03-26 19:04:28 +00:00
09b8144080 Merge pull request 'Implemented password strength test feature/106-password_strength' (#115) from feature/106-password_strength into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #115
2021-03-26 19:03:03 +00:00
f1e6fb4ce7 Merge branch 'dev' into feature/106-password_strength 2021-03-26 19:59:47 +01:00
4167819e7a Formatting🛠
ref #106
2021-03-26 19:52:31 +01:00
5bd3a463f0 Sorted translations 🌍
ref #106
2021-03-26 19:51:57 +01:00
79c447b4c6 Added translations
ref #106
2021-03-26 19:51:27 +01:00
540304f947 User creation can now only be triggered if pw is strong enoug
ref #106
2021-03-26 19:48:42 +01:00
75d8f7331b Reset can now only be triggered if pw is strong enoug
ref #106
2021-03-26 19:47:26 +01:00
b2509e9e53 Module now exports functions that check if a password is strong enough and equal to a potential confirmation field
ref #106
2021-03-26 19:45:53 +01:00
7862f44653 Now using pw strength component for user creation
ref #106
2021-03-26 19:31:21 +01:00
962dd0c1bb Added missing exports
ref #106
2021-03-26 19:29:47 +01:00
5d5f7c7f5c Now using pw strength component for reset
ref #106
2021-03-26 19:29:37 +01:00
6aaf838451 Now using pw strength component
ref #106
2021-03-26 19:29:25 +01:00
ad3bd312e9 Added a password strength verification
ref #106
2021-03-26 19:26:26 +01:00
5fa9939696 Added more cirteria to the password strength component
ref #106
2021-03-26 19:02:09 +01:00
4956bb0e9c Implemented a custom password strength component
ref #106
2021-03-26 18:47:24 +01:00
008027db0e added windicss settings for VSCode
ref #108
2021-03-25 18:57:33 +01:00
aec5e3473e for await fix - ViteJS
ref #108
2021-03-25 18:56:18 +01:00
95c8fde72f updated default entrypoint
ref #108
2021-03-25 18:56:02 +01:00
0f32968fae 🐳 new Dockerfiles
ref #108
2021-03-25 18:55:43 +01:00
ae79e9fea1 basic ViteJS migration
ref #108
2021-03-25 18:55:24 +01:00
66 changed files with 2109 additions and 708 deletions

6
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,6 @@
FROM mcr.microsoft.com/vscode/devcontainers/base:alpine-3.12
RUN apk update
RUN apk add --upgrade nodejs-current npm
RUN npm i -g yarn rimraf
RUN rimraf node_modules
RUN yarn set version berry

View File

@@ -0,0 +1,20 @@
{
"name": "Node.js",
"build": {
"dockerfile": "Dockerfile"
},
"settings": {
"terminal.integrated.shell.linux": "/bin/sh"
},
"extensions": [
"dbaeumer.vscode-eslint",
"2gua.rainbow-brackets",
"christian-kohler.npm-intellisense",
"remimarsal.prettier-now",
"svelte.svelte-vscode",
"lokalise.i18n-ally",
"fivethree.vscode-svelte-snippets",
"voorjaar.windicss-intellisense"
],
"postCreateCommand": "yarn && yarn dev --open"
}

View File

@@ -1,3 +1 @@
public/env.sample.js
public/workbox-*.js
public/workbox-*.js.map
public/env.sample.js

View File

@@ -27,7 +27,7 @@ name: build:dev
steps:
- name: run full license export
depends_on: ["clone"]
image: node:alpine
image: registry.odit.services/hub/library/node:alpine
commands:
- yarn
- yarn licenses:export

9
.gitignore vendored
View File

@@ -1,11 +1,10 @@
node_modules
build
package-lock.json
yarn.lock
*.map
public/env.js
public/sw.js
public/index.html
public/workbox-*.js
svelte.config.js
public/index.html
/dist
.yarn
.pnp.js
.yarnrc.yml

View File

@@ -5,7 +5,8 @@
"remimarsal.prettier-now",
"svelte.svelte-vscode",
"lokalise.i18n-ally",
"fivethree.vscode-svelte-snippets"
"fivethree.vscode-svelte-snippets",
"voorjaar.windicss-intellisense"
],
"unwantedRecommendations": [
"antfu.i18n-ally"

View File

@@ -1,4 +1,5 @@
{
"i18n-ally.localesPaths": "src/locales",
"i18n-ally.keystyle": "nested"
"i18n-ally.keystyle": "nested",
"windicss.enableCodeFolding": false,
}

View File

@@ -2,8 +2,241 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [0.15.2](https://git.odit.services/lfk/frontend/compare/0.15.1...0.15.2)
- 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)
> 30 March 2021
- 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)
- 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)
- 🚀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)
- 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)
- 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)
#### [0.10.0](https://git.odit.services/lfk/frontend/compare/0.9.1...0.10.0)
> 26 March 2021
- Added translations [`79c447b`](https://git.odit.services/lfk/frontend/commit/79c447b4c65e55ebb5af71fb0b09174c36e2cecf)
- Sorted translations 🌍 [`5bd3a46`](https://git.odit.services/lfk/frontend/commit/5bd3a463f00abaf2c98ab554f88e5542d01f364a)
- Reset can now only be triggered if pw is strong enoug [`75d8f73`](https://git.odit.services/lfk/frontend/commit/75d8f7331b6ae78f3979bb62148188a16f83cb8d)
- Module now exports functions that check if a password is strong enough and equal to a potential confirmation field [`b2509e9`](https://git.odit.services/lfk/frontend/commit/b2509e9e53ab6b51dfd55e26712e8928160cd64b)
- 🚀RELEASE v0.10.0 [`f7fc196`](https://git.odit.services/lfk/frontend/commit/f7fc1967a50f302af1d8b668628be2f4ab2975a3)
- Added more cirteria to the password strength component [`5fa9939`](https://git.odit.services/lfk/frontend/commit/5fa9939696a35d60d762feb0cebef61d31869218)
- Now using pw strength component [`6aaf838`](https://git.odit.services/lfk/frontend/commit/6aaf8384512185a3a319ce6b3e2505e910468e64)
- Added a password strength verification [`ad3bd31`](https://git.odit.services/lfk/frontend/commit/ad3bd312e9a5785f81029ea2b7e302ea1addd988)
- Implemented a custom password strength component [`4956bb0`](https://git.odit.services/lfk/frontend/commit/4956bb0e9c3c1d22d60e849aea5664e35330f897)
- User creation can now only be triggered if pw is strong enoug [`540304f`](https://git.odit.services/lfk/frontend/commit/540304f947f60a7072c592ca8088996ce7e95cb4)
- Now using pw strength component for user creation [`7862f44`](https://git.odit.services/lfk/frontend/commit/7862f446532903f1a2eac7b21d5c80c3245785e5)
- Added missing exports [`962dd0c`](https://git.odit.services/lfk/frontend/commit/962dd0c1bbc0df7f20bcec5b4247188c8935c87e)
- new license file version [CI SKIP] [`aedb8a7`](https://git.odit.services/lfk/frontend/commit/aedb8a765ba053545adbba9eb014b3bb0e5aac8c)
- Bumped lfk-client version 🔝 [`cf58bd1`](https://git.odit.services/lfk/frontend/commit/cf58bd15c3541c417ab2be83d96135e931a2b6f6)
- new license file version [CI SKIP] [`34f4f68`](https://git.odit.services/lfk/frontend/commit/34f4f68524918fd3d1963966a1e259d5b60efaca)
- Merge pull request 'Implemented password strength test feature/106-password_strength' (#115) from feature/106-password_strength into dev [`09b8144`](https://git.odit.services/lfk/frontend/commit/09b81440804cf98303fcb723a9717d6d0f432da8)
- Formatting🛠 [`4167819`](https://git.odit.services/lfk/frontend/commit/4167819e7a864d3b1dd95ba48ab1525a454f7f30)
- Now using pw strength component for reset [`5d5f7c7`](https://git.odit.services/lfk/frontend/commit/5d5f7c7f5c6a69146f41996f4facfeff95791be0)
#### [0.9.1](https://git.odit.services/lfk/frontend/compare/0.9.0...0.9.1)
> 26 March 2021
- 🚀RELEASE v0.9.1 [`2ca63fd`](https://git.odit.services/lfk/frontend/commit/2ca63fd1f675f0da2b18ba43095074dd4823991d)
- Merge pull request 'Org selfservice Link feature/112-org_registration_links' (#114) from feature/112-org_registration_links into dev [`a5d25e7`](https://git.odit.services/lfk/frontend/commit/a5d25e7d92c7c37e90dbb4ba74b787873f920c6b)
- Added checkbox to enable registration [`f9fe793`](https://git.odit.services/lfk/frontend/commit/f9fe79357317653b46c09eb95b0db13845cddcf9)
- Sorted translations [`c074c12`](https://git.odit.services/lfk/frontend/commit/c074c12be75f285612f7a732c106404d9fb4538a)

View File

@@ -1,18 +1,12 @@
FROM node:15.5.1-alpine3.12
FROM registry.odit.services/hub/library/node:15.14.0-alpine3.13
WORKDIR /app
RUN npm i -g pnpm
COPY package.json ./
RUN pnpm i
COPY package.json *.config.js workbox-config.js template-copy.js index.template.html s-config.template.js ./
RUN yarn
COPY package.json *.config.js postcss.config.cjs index.html ./
COPY src ./src
COPY public ./public
RUN pnpm run build
RUN yarn build
# final image
FROM alpine
COPY --from=0 /app/build /app
RUN rm -rf /app/build/_dist_/components
RUN rm -rf /app/build/_dist_/locales
RUN rm -rf /app/build-manifest.json
FROM fholzer/nginx-brotli:v1.19.1
COPY --from=1 /app /usr/share/nginx/html
FROM registry.odit.services/hub/fholzer/nginx-brotli:v1.19.1
COPY --from=0 /app/dist /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/nginx.conf

22
README.md Normal file
View File

@@ -0,0 +1,22 @@
# @odit/lfk-frontend
## ✒️ Overview
This is an API client for [https://git.odit.services/lfk/backend](@lfk/backend)
- WebApp built with [Svelte](https://svelte.dev), [WindiCSS](https://windicss.org/) (to compile [TailwindCSS](https://tailwindcss.com/)) and [Vite](https://vitejs.dev).
This application is intended for use by admin users/ members only.
## 🚀 Getting Started
```
yarn
```
## Development
```
yarn dev
/
yarn dev --open
```
## Build
```
yarn build
```

View File

@@ -10,14 +10,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Lauf Für Kaya! - Admin" />
<title>Lauf für Kaya! - Admin</title>
__TAILWIND_INSERT__
</head>
<body>
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.9.1-RELEASE_INFO</span>
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.15.2-RELEASE_INFO</span>
<noscript>You need to enable JavaScript to run this app.</noscript>
<script src="/env.js"></script>
<script defer type="module" src="/_dist_/index.js"></script>
<script type="module" src="/src/main.js"></script>
</body>
</html>

View File

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

View File

@@ -1,45 +1,40 @@
{
"name": "@odit/lfk-frontend",
"version": "0.9.1",
"version": "0.15.2",
"scripts": {
"i18n-order": "node order.js",
"dev:all": "yarn prebuild && snowpack dev",
"dev": "cross-env NODE_ENV_ODIT=development_fast node template-copy.js && yarn build:sw && snowpack dev",
"build": "yarn prebuild && snowpack build",
"prebuild": "cross-env NODE_ENV_ODIT=production node template-copy.js && yarn build:sw",
"build:sw": "workbox generateSW workbox-config.js",
"dev": "vite",
"build": "vite build",
"release": "release-it",
"licenses:export": "license-exporter --json -o public"
},
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"@odit/lfk-client-js": "0.7.0",
"csvtojson": "^2.0.10",
"gridjs": "3.3.0",
"localforage": "1.9.0",
"marked": "^2.0.1",
"svelte-focus-trap": "1.0.1",
"svelte-i18n": "3.3.7",
"svelte-select": "^3.17.0",
"tailwindcss": "2.0.3",
"tinro": "0.6.1",
"toastify-js": "1.9.3",
"validator": "13.5.2",
"xlsx": "^0.16.9"
},
"devDependencies": {
"@odit/license-exporter": "^0.0.11",
"@snowpack/plugin-svelte": "3.5.2",
"auto-changelog": "^2.2.1",
"autoprefixer": "10.2.5",
"cross-env": "^7.0.3",
"postcss": "8.2.8",
"postcss-load-config": "3.0.1",
"release-it": "^14.4.1",
"snowpack": "3.0.13",
"svelte": "3.35.0",
"svelte-preprocess": "4.6.9",
"workbox-cli": "6.1.2"
"@odit/lfk-client-js": "0.11.0",
"@odit/license-exporter": "0.0.11",
"@sveltejs/vite-plugin-svelte": "1.0.0-next.6",
"@types/html-minifier": "4.0.0",
"auto-changelog": "2.2.1",
"autoprefixer": "^10.2.5",
"check-password-strength": "2.0.2",
"csvtojson": "2.0.10",
"gridjs": "3.4.0",
"html-minifier": "4.0.0",
"localforage": "1.9.0",
"marked": "2.0.3",
"postcss": "^8.2.10",
"release-it": "14.6.1",
"svelte": "3.37.0",
"svelte-focus-trap": "1.2.0",
"svelte-i18n": "3.3.9",
"svelte-preprocess": "^4.7.0",
"svelte-select": "3.17.0",
"tailwindcss": "^2.1.1",
"tinro": "0.6.1",
"toastify-js": "1.10.0",
"validator": "13.5.2",
"vite": "2.1.5",
"xlsx": "0.16.9"
},
"release-it": {
"git": {
@@ -55,7 +50,7 @@
"publish": false
},
"hooks": {
"after:bump": "npx auto-changelog --commit-limit false -p -u --hide-credit && git add CHANGELOG.md && node versionbuilder.js && git add index.template.html && node order.js && git add src/locales"
"after:bump": "npx auto-changelog --commit-limit false -p -u --hide-credit && git add CHANGELOG.md && node versionbuilder.js && git add index.html && node order.js && git add src/locales"
}
}
}

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 = {
baseurl: 'http://localhost:4010',
baseurl_documentserver: 'http://localhost:4010/documents',
documentserver_key: 'NqZSYTy5AFQ7MppbLW5moqpTk7u7YrNUHKYhKYuThnnya2WpCOIU694hIZT1FzYe',
// optional
default_username: 'demo',

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +0,0 @@
const sveltePreprocess = require('svelte-preprocess');
const preprocess = sveltePreprocess(__insert__);
module.exports = {
preprocess
};

View File

@@ -1,26 +0,0 @@
/** @type {import("snowpack").SnowpackUserConfig } */
module.exports = {
mount: {
public: '/',
src: '/_dist_'
},
plugins: [ '@snowpack/plugin-svelte' ],
routes: [
/* Enable an SPA Fallback in development: */
{ match: 'routes', src: '.*', dest: '/index.html' }
],
packageOptions: {
/* ... */
sourceMap: false
},
devOptions: {
/* ... */
},
buildOptions: {
/* ... */
},
alias: {
/* ... */
},
optimize: { bundle: true, minify: true }
};

View File

@@ -1,224 +1,221 @@
<script>
import "./TailwindStyles.svelte";
import "toastify-js/src/toastify.css";
import "gridjs/dist/theme/mermaid.css";
import { Route, router } from "tinro";
router.subscribe((routeInfo) => {
window.scrollTo(0, 0);
});
if (config.prefersHashRouting) {
if (config.prefersHashRouting === true) {
router.useHashNavigation();
}
}
import localForage from "localforage";
import { addMessages, init, getLocaleFromNavigator } from "svelte-i18n";
import en from "./locales/en.json";
import de from "./locales/de.json";
addMessages("en", en);
addMessages("de", de);
init({
fallbackLocale: "en",
initialLocale: getLocaleFromNavigator(),
});
localForage.config({
name: "lfk_admin",
version: 1.0,
storeName: "lfk_admin",
description: "LfK! admin dashbaord",
});
window.onunhandledrejection = (event) => {
if (event.reason.toString() == "Error: Unauthorized") {
console.log("Found 1");
localForage.clear();
location.replace("/");
}
};
//
import Login from "./components/auth/Login.svelte";
import Dashboard from "./components/dashboard/Dashboard.svelte";
import store from "./store.js";
import ForgotPassword from "./components/auth/ForgotPassword.svelte";
import MainDashContent from "./components/dashboard/MainDashContent.svelte";
import Users from "./components/users/Users.svelte";
import About from "./components/general/About.svelte";
import Settings from "./components/settings/Settings.svelte";
import Transition from "./components/base/Transition.svelte";
import Orgs from "./components/orgs/Orgs.svelte";
import Runners from "./components/runners/Runners.svelte";
import Footer from "./components/general/Footer.svelte";
import TracksOverview from "./components/tracks/TracksOverview.svelte";
import OrgDetail from "./components/orgs/OrgDetail.svelte";
import Teams from "./components/teams/Teams.svelte";
import { OpenAPI } from "@odit/lfk-client-js";
import UserDetail from "./components/users/UserDetail.svelte";
OpenAPI.BASE = config.baseurl;
import { register as registerSW } from "./swmodule";
import TeamDetail from "./components/teams/TeamDetail.svelte";
import UserPermissions from "./components/users/UserPermissions.svelte";
import GroupPermissions from "./components/groups/GroupPermissions.svelte";
import RunnerDetail from "./components/runners/RunnerDetail.svelte";
import Imprint from "./components/general/Imprint.svelte";
import Privacy from "./components/general/Privacy.svelte";
import ResetPassword from "./components/auth/ResetPassword.svelte";
import Contacts from "./components/contacts/Contacts.svelte";
import ContactDetail from "./components/contacts/ContactDetail.svelte";
import Donors from "./components/donors/Donors.svelte";
import Groups from "./components/groups/Groups.svelte";
import DonorDetail from "./components/donors/DonorDetail.svelte";
import Donations from "./components/donations/Donations.svelte";
import DonationDetail from "./components/donations/DonationDetail.svelte";
import GroupDetail from "./components/groups/GroupDetail.svelte";
import ScanStations from "./components/scanstations/ScanStations.svelte";
import ScanStationDetail from "./components/scanstations/ScanStationDetail.svelte";
import Scans from "./components/scans/Scans.svelte";
import ScanDetail from "./components/scans/ScanDetail.svelte";
import Cards from "./components/cards/Cards.svelte";
store.init();
registerSW();
</script>
<Route>
{#if $router.path === '/forgot_password'}
<Route path="/forgot_password">
<ForgotPassword />
</Route>
{:else if $router.path.includes('/reset')}
<Route path="/reset/:resetkey" let:params>
<ResetPassword {params} />
</Route>
{:else if $router.path === '/about'}
<Route path="/about">
<About />
</Route>
{:else if $router.path === '/imprint'}
<Route path="/imprint">
<Imprint />
</Route>
{:else if $router.path === '/privacy'}
<Route path="/privacy">
<Privacy />
</Route>
{:else if $store.isLoggedIn}
<Dashboard>
<Transition>
<Route path="/">
<MainDashContent />
</Route>
<Route path="/users/*">
<Route path="/">
<Users />
</Route>
<Route path="/:userid/*" let:params>
<Route path="/">
<UserDetail {params} />
</Route>
<Route path="/permissions/">
<UserPermissions {params} />
</Route>
</Route>
</Route>
<Route path="/groups/*">
<Route path="/">
<Groups />
</Route>
<Route path="/:groupid/*" let:params>
<Route path="/">
<GroupDetail {params} />
</Route>
<Route path="/permissions/">
<GroupPermissions {params} />
</Route>
</Route>
</Route>
<Route path="/tracks/*">
<Route path="/">
<TracksOverview />
</Route>
<Route path="/:trackid" let:params />
</Route>
<Route path="/runners/*">
<Route path="/">
<Runners />
</Route>
<Route path="/:runnerid" let:params>
<RunnerDetail {params} />
</Route>
</Route>
<Route path="/teams/*">
<Route path="/">
<Teams />
</Route>
<Route path="/:teamid" let:params>
<TeamDetail {params} />
</Route>
</Route>
<Route path="/contacts/*">
<Route path="/">
<Contacts />
</Route>
<Route path="/:contact" let:params>
<ContactDetail {params} />
</Route>
</Route>
<Route path="/orgs/*">
<Route path="/">
<Orgs />
</Route>
<Route path="/:orgid" let:params>
<OrgDetail {params} />
</Route>
</Route>
<Route path="/donors/*">
<Route path="/">
<Donors />
</Route>
<Route path="/:donorid" let:params>
<DonorDetail {params} />
</Route>
</Route>
<Route path="/donations/*">
<Route path="/">
<Donations />
</Route>
<Route path="/:donationid" let:params>
<DonationDetail {params} />
</Route>
</Route>
<Route path="/cards/*">
<Route path="/">
<Cards />
</Route>
<!-- <Route path="/:scanid" let:params>
<ScanDetail {params} />
</Route> -->
</Route>
<Route path="/scans/*">
<Route path="/">
<Scans />
</Route>
<Route path="/:scanid" let:params>
<ScanDetail {params} />
</Route>
</Route>
<Route path="/scanstations/*">
<Route path="/">
<ScanStations />
</Route>
<Route path="/:stationid" let:params>
<ScanStationDetail {params} />
</Route>
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/settings">
<Settings />
</Route>
</Transition>
<Footer />
</Dashboard>
{:else}
<Login />
{/if}
</Route>
<script>
import "toastify-js/src/toastify.css";
import "gridjs/dist/theme/mermaid.css";
import { Route, router } from "tinro";
router.subscribe((routeInfo) => {
window.scrollTo(0, 0);
});
if (config.prefersHashRouting) {
if (config.prefersHashRouting === true) {
router.useHashNavigation();
}
}
import localForage from "localforage";
import { addMessages, init, getLocaleFromNavigator } from "svelte-i18n";
import en from "./locales/en.json";
import de from "./locales/de.json";
addMessages("en", en);
addMessages("de", de);
init({
fallbackLocale: "en",
initialLocale: getLocaleFromNavigator(),
});
localForage.config({
name: "lfk_admin",
version: 1.0,
storeName: "lfk_admin",
description: "LfK! admin dashbaord",
});
window.onunhandledrejection = (event) => {
if (event.reason.toString() == "Error: Unauthorized") {
console.log("Found 1");
localForage.clear();
location.replace("/");
}
};
//
import Login from "./components/auth/Login.svelte";
import Dashboard from "./components/dashboard/Dashboard.svelte";
import store from "./store.js";
import ForgotPassword from "./components/auth/ForgotPassword.svelte";
import MainDashContent from "./components/dashboard/MainDashContent.svelte";
import Users from "./components/users/Users.svelte";
import About from "./components/general/About.svelte";
import Settings from "./components/settings/Settings.svelte";
import Transition from "./components/base/Transition.svelte";
import Orgs from "./components/orgs/Orgs.svelte";
import Runners from "./components/runners/Runners.svelte";
import Footer from "./components/general/Footer.svelte";
import TracksOverview from "./components/tracks/TracksOverview.svelte";
import OrgDetail from "./components/orgs/OrgDetail.svelte";
import Teams from "./components/teams/Teams.svelte";
import { OpenAPI } from "@odit/lfk-client-js";
import UserDetail from "./components/users/UserDetail.svelte";
OpenAPI.BASE = config.baseurl;
import TeamDetail from "./components/teams/TeamDetail.svelte";
import UserPermissions from "./components/users/UserPermissions.svelte";
import GroupPermissions from "./components/groups/GroupPermissions.svelte";
import RunnerDetail from "./components/runners/RunnerDetail.svelte";
import Imprint from "./components/general/Imprint.svelte";
import Privacy from "./components/general/Privacy.svelte";
import ResetPassword from "./components/auth/ResetPassword.svelte";
import Contacts from "./components/contacts/Contacts.svelte";
import ContactDetail from "./components/contacts/ContactDetail.svelte";
import Donors from "./components/donors/Donors.svelte";
import Groups from "./components/groups/Groups.svelte";
import DonorDetail from "./components/donors/DonorDetail.svelte";
import Donations from "./components/donations/Donations.svelte";
import DonationDetail from "./components/donations/DonationDetail.svelte";
import GroupDetail from "./components/groups/GroupDetail.svelte";
import ScanStations from "./components/scanstations/ScanStations.svelte";
import ScanStationDetail from "./components/scanstations/ScanStationDetail.svelte";
import Scans from "./components/scans/Scans.svelte";
import ScanDetail from "./components/scans/ScanDetail.svelte";
import Cards from "./components/cards/Cards.svelte";
store.init();
</script>
<Route>
{#if $router.path === '/forgot_password'}
<Route path="/forgot_password">
<ForgotPassword />
</Route>
{:else if $router.path.includes('/reset')}
<Route path="/reset/:resetkey" let:params>
<ResetPassword {params} />
</Route>
{:else if $router.path === '/about'}
<Route path="/about">
<About />
</Route>
{:else if $router.path === '/imprint'}
<Route path="/imprint">
<Imprint />
</Route>
{:else if $router.path === '/privacy'}
<Route path="/privacy">
<Privacy />
</Route>
{:else if $store.isLoggedIn}
<Dashboard>
<Transition>
<Route path="/">
<MainDashContent />
</Route>
<Route path="/users/*">
<Route path="/">
<Users />
</Route>
<Route path="/:userid/*" let:params>
<Route path="/">
<UserDetail {params} />
</Route>
<Route path="/permissions/">
<UserPermissions {params} />
</Route>
</Route>
</Route>
<Route path="/groups/*">
<Route path="/">
<Groups />
</Route>
<Route path="/:groupid/*" let:params>
<Route path="/">
<GroupDetail {params} />
</Route>
<Route path="/permissions/">
<GroupPermissions {params} />
</Route>
</Route>
</Route>
<Route path="/tracks/*">
<Route path="/">
<TracksOverview />
</Route>
<Route path="/:trackid" let:params />
</Route>
<Route path="/runners/*">
<Route path="/">
<Runners />
</Route>
<Route path="/:runnerid" let:params>
<RunnerDetail {params} />
</Route>
</Route>
<Route path="/teams/*">
<Route path="/">
<Teams />
</Route>
<Route path="/:teamid" let:params>
<TeamDetail {params} />
</Route>
</Route>
<Route path="/contacts/*">
<Route path="/">
<Contacts />
</Route>
<Route path="/:contact" let:params>
<ContactDetail {params} />
</Route>
</Route>
<Route path="/orgs/*">
<Route path="/">
<Orgs />
</Route>
<Route path="/:orgid" let:params>
<OrgDetail {params} />
</Route>
</Route>
<Route path="/donors/*">
<Route path="/">
<Donors />
</Route>
<Route path="/:donorid" let:params>
<DonorDetail {params} />
</Route>
</Route>
<Route path="/donations/*">
<Route path="/">
<Donations />
</Route>
<Route path="/:donationid" let:params>
<DonationDetail {params} />
</Route>
</Route>
<Route path="/cards/*">
<Route path="/">
<Cards />
</Route>
<!-- <Route path="/:scanid" let:params>
<ScanDetail {params} />
</Route> -->
</Route>
<Route path="/scans/*">
<Route path="/">
<Scans />
</Route>
<Route path="/:scanid" let:params>
<ScanDetail {params} />
</Route>
</Route>
<Route path="/scanstations/*">
<Route path="/">
<ScanStations />
</Route>
<Route path="/:stationid" let:params>
<ScanStationDetail {params} />
</Route>
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/settings">
<Settings />
</Route>
</Transition>
<Footer />
</Dashboard>
{:else}
<Login />
{/if}
</Route>

View File

@@ -1,6 +0,0 @@
<style global>
/*! @import */
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>

View File

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

View File

@@ -0,0 +1,52 @@
<script context="module">
import { passwordStrength } from "check-password-strength";
export function password_strong_enough(password_change) {
let strength = passwordStrength(password_change);
return (
strength?.contains.includes("lowercase") &&
strength?.contains.includes("uppercase") &&
strength?.contains.includes("number") &&
strength?.length > 9
);
}
export function password_strong_enough_and_equal(
password_change,
password_confirm
) {
return (
password_strong_enough(password_change) &&
password_change === password_confirm
);
}
</script>
<script>
import { getLocaleFromNavigator, _ } from "svelte-i18n";
import { passwordStrength as Strength } from "check-password-strength";
export let password_change;
export let password_confirm;
$: strength = Strength(password_change);
$: passwords_match =
!password_confirm || password_confirm === password_change;
</script>
<div class="ml-4">
<ul class="list-disc font-medium tracking-wide text-red-500 text-xs">
{#if !strength.contains.includes('lowercase')}
<li>{$_('must-contain-a-lowercase-letter')}</li>
{/if}
{#if !strength.contains.includes('uppercase')}
<li>{$_('must-contain-a-uppercase-letter')}</li>
{/if}
{#if !strength.contains.includes('number')}
<li>{$_('must-contain-a-number')}</li>
{/if}
{#if !(strength.length > 9)}
<li>{$_('must-be-at-least-10-characters-long')}</li>
{/if}
{#if !(passwords_match == true)}
<li>{$_('passwords-dont-match')}</li>
{/if}
</ul>
</div>

View File

@@ -1,38 +1,43 @@
<script>
import { AuthService } from "@odit/lfk-client-js";
import { AuthService } from "@odit/lfk-client-js";
import { _ } from "svelte-i18n";
import Toastify from "toastify-js";
import "toastify-js/src/toastify.css";
import PasswordStrength, {
password_strong_enough,
} from "../auth/PasswordStrength.svelte";
let state = "reset_in_progress";
let password = "";
export let params;
function set_new_password() {
if(password.trim() !== ""){
Toastify({
text: $_('password-reset-in-progress'),
duration: 3500,
}).showToast();
AuthService.authControllerResetPassword(atob(params.resetkey),{ password })
if (password.trim() !== "") {
Toastify({
text: $_("password-reset-in-progress"),
duration: 3500,
}).showToast();
AuthService.authControllerResetPassword(atob(params.resetkey), {
password,
})
.then((resp) => {
Toastify({
text: $_('password-reset-successful'),
text: $_("password-reset-successful"),
duration: 3500,
}).showToast();
state="reset_success";
state = "reset_success";
})
.catch((err) => {
state="reset_error";
state = "reset_error";
});
} else {
} else {
Toastify({
text: $_('please-provide-a-password'),
text: $_("please-provide-a-password"),
duration: 3500,
}).showToast();
}
}
</script>
{#if state==="reset_success"}
{#if state === 'reset_success'}
<div class="min-h-screen flex items-center justify-center bg-gray-100">
<div class="max-w-md w-full py-12 px-6">
<img style="height:10rem;" class="mx-auto" src="/lfk-logo.png" alt="" />
@@ -56,31 +61,31 @@
</div>
</div>
</div>
{:else if state==="reset_error"}
<div class="min-h-screen flex items-center justify-center bg-gray-100">
<div class="max-w-md w-full py-12 px-6">
<img style="height:10rem;" class="mx-auto" src="/lfk-logo.png" alt="" />
<p class="mt-6 text-lg text-center font-bold text-gray-900">
{$_('application_name')}
</p>
<p class="mt-2 mb-2 text-sm text-center text-gray-900 font-bold">
{$_('password-reset-failed')}
</p>
<p class="mt-2 mb-2 text-sm text-center text-gray-900">
{$_('please-request-a-new-reset-mail')}
</p>
<div class="mt-6">
{:else if state === 'reset_error'}
<div class="min-h-screen flex items-center justify-center bg-gray-100">
<div class="max-w-md w-full py-12 px-6">
<img style="height:10rem;" class="mx-auto" src="/lfk-logo.png" alt="" />
<p class="mt-6 text-lg text-center font-bold text-gray-900">
{$_('application_name')}
</p>
<p class="mt-2 mb-2 text-sm text-center text-gray-900 font-bold">
{$_('password-reset-failed')}
</p>
<p class="mt-2 mb-2 text-sm text-center text-gray-900">
{$_('please-request-a-new-reset-mail')}
</p>
<div class="mt-6">
<a
href="/forgot_password/"
class="text-center relative block w-full py-2 px-3 border border-transparent rounded-md text-white font-semibold bg-gray-800 hover:bg-gray-700 focus:bg-gray-900 focus:outline-none focus:shadow-outline sm:text-sm">
{$_('request-a-new-reset-mail')}
</a>
<div class="mt-6">
<a
href="/forgot_password/"
class="text-center relative block w-full py-2 px-3 border border-transparent rounded-md text-white font-semibold bg-gray-800 hover:bg-gray-700 focus:bg-gray-900 focus:outline-none focus:shadow-outline sm:text-sm">
{$_('request-a-new-reset-mail')}
</a>
</div>
</div>
</div>
</div>
</div>
{:else if state==="reset_in_progress"}
{:else if state === 'reset_in_progress'}
<div class="min-h-screen flex items-center justify-center bg-gray-100">
<div class="max-w-md w-full py-12 px-6">
<img style="height:10rem;" class="mx-auto" src="/lfk-logo.png" alt="" />
@@ -102,11 +107,14 @@
placeholder={$_('new-password')}
bind:value={password} />
</div>
<PasswordStrength bind:password_change={password} />
</div>
<div class="mt-5">
<button
on:click={set_new_password}
disabled={!password_strong_enough(password)}
class:opacity-50={!password_strong_enough(password)}
type="submit"
class="relative block w-full py-2 px-3 border border-transparent rounded-md text-white font-semibold bg-gray-800 hover:bg-gray-700 focus:bg-gray-900 focus:outline-none focus:shadow-outline sm:text-sm">
<span class="absolute left-0 inset-y pl-3">

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

@@ -22,19 +22,19 @@
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
submit_with_print();
}
}
};
})();
function submit() {
function submit_without_print() {
if (processed_last_submit === true) {
processed_last_submit = false;
const toast = Toastify({
text: $_("creating-blanco-cards"),
duration: -1,
}).showToast();
RunnerCardService.runnerCardControllerPostBlancoBulk(card_count)
RunnerCardService.runnerCardControllerPostBlancoBulk(card_count, false)
.then((result) => {
bulk_modal_open = false;
//
@@ -54,6 +54,80 @@
});
}
}
function submit_with_print() {
if (processed_last_submit === true) {
processed_last_submit = false;
const toast = Toastify({
text: $_("creating-blanco-cards"),
duration: -1,
}).showToast();
RunnerCardService.runnerCardControllerPostBlancoBulk(card_count, true)
.then((result) => {
bulk_modal_open = false;
//
Toastify({
text: $_("created-blanco-cards"),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
current_cards = current_cards.concat(result);
const toast = Toastify({
text: $_("generating-pdf"),
duration: -1,
}).showToast();
fetch(
`${config.baseurl_documentserver}/cards?&download=true&key=${config.documentserver_key}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(result),
}
)
.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 = "Bulkcards.pdf";
document.body.appendChild(a);
a.click();
a.remove();
toast.hideToast();
Toastify({
text: $_("pdf-successfully-generated"),
duration: 3500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
})
.catch((err) => {
console.error(err);
});
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
//
toast.hideToast();
});
}
}
</script>
{#if bulk_modal_open}
@@ -75,14 +149,14 @@
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"
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-2xl 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">
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w- 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"
@@ -138,17 +212,25 @@
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit}
on:click={submit_with_print}
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')}
{$_('create-and-generate-pdf')}
</button>
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit_without_print}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-400 text-base font-medium text-white hover:bg-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
{$_('create-without-pdf')}
</button>
<button
on:click={() => {
bulk_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">
class="mr-auto 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>

View File

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

View File

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

View File

@@ -12,11 +12,21 @@
}
</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">
<nav
class:-translate-x-full={!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 md:translate-x-0 bg-gray-50">
<div
class:collapsed_navigation={!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">
<a href="/" class="flex items-center px-4 py-5">
<img src="/lfk-logo.png" alt="Logo" class="h-10" />
<h3 class="text-lg">Lauf für Kaya! Admin</h3>
@@ -297,14 +307,15 @@
<span>{$_('logout')}</span>
</span>
</nav>
</nav>
</div>
<div class="ml-0 transition md:ml-60">
<header
on:click={() => {
navOpen = true;
}}
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
class="w-4 h-4"
xmlns="http://www.w3.org/2000/svg"
@@ -318,10 +329,13 @@
<NoComponentLoaded />
</slot>
</div>
<div
on:click={() => {
navOpen = false;
}}
class:hidden={!navOpen}
class="fixed inset-0 z-10 w-screen h-screen bg-black bg-opacity-25 md:hidden" />
{#if navOpen === true}
<div
on:click={() => {
navOpen = false;
console.log({ navOpen });
}}
class:hidden={!navOpen}
class="fixed inset-0 z-10 w-screen h-screen bg-black bg-opacity-25 md:hidden" />
{/if}
</section>

View File

@@ -9,6 +9,7 @@
} from "@odit/lfk-client-js";
import Select from "svelte-select";
import Toastify from "toastify-js";
import { is_promise } from "svelte/internal";
export let modal_open;
export let current_donations;
const getDonorLabel = (option) =>
@@ -24,6 +25,7 @@
$: donors = [];
$: runners = [];
$: is_fixed = false;
$: is_paid = false;
DonorService.donorControllerGetAll().then((val) => {
donors = val.map((r) => {
return { label: getDonorLabel(r), value: r };
@@ -57,14 +59,18 @@
let amount_cent = Math.floor(amount_input * 100);
processed_last_submit = false;
const toast = Toastify({
text: "adding donation",
text: $_('adding-donation'),
duration: -1,
}).showToast();
if (is_fixed) {
let postdata = {
donor,
amount: amount_cent,
paidAmount: 0
};
if(is_paid){
postdata.paidAmount = amount_cent;
}
DonationService.donationControllerPostFixed(postdata)
.then((result) => {
donor = donors[0].id || 0;
@@ -73,7 +79,7 @@
modal_open = false;
//
Toastify({
text: "donation_added",
text: $_('donation_added'),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
@@ -102,7 +108,7 @@
modal_open = false;
//
Toastify({
text: "donation_added",
text: $_('donation_added'),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
@@ -123,7 +129,7 @@
</script>
<style>
input:before {
.toggle:before {
content: "";
position: absolute;
width: 1.25rem;
@@ -137,12 +143,12 @@
transition: 0.2s ease-in-out;
}
input:checked {
.toggle:checked {
/* @apply: bg-indigo-400; */
background-color: #7f9cf5;
}
input:checked:before {
.toggle:checked:before {
left: 1.25rem;
}
</style>
@@ -195,7 +201,7 @@
class="ml-2 text-base"
class:text-gray-300={is_fixed}>{$_('distance-donation')}</span>
<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"
bind:checked={is_fixed} />
<span
@@ -267,6 +273,29 @@
</span>
{/if}
</div>
{#if is_fixed}
<div class="col-span-6">
<label
for="paid"
class="block text-sm font-medium text-gray-700">{$_('already-paid')}</label>
<p class="text-gray-500">
<input
id="paid"
bind:checked={is_paid}
name="paid"
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" >
<span class="align-text-bottom">
{#if is_paid}
{$_('paid')}
{:else}
{$_('open')}
{/if}
</span>
</p>
</div>
{/if}
</div>
</div>
</div>

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

View File

@@ -4,9 +4,14 @@
import store from "../../store";
import Toastify from "toastify-js";
import DonationsEmptyState from "./DonationsEmptyState.svelte";
import AddDonationPaymentModal from "./AddDonationPaymentModal.svelte";
$: searchvalue = "";
$: active_deletes = [];
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(
(val) => {
current_donations = val;
@@ -18,8 +23,15 @@
}
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>
<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')}
{#await donations_promise}
<div
@@ -63,6 +75,16 @@
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('donation-amount')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('paid-amount')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('status')}
</th>
<th scope="col" class="relative px-6 py-3">
<span class="sr-only">{$_('action')}</span>
</th>
@@ -132,6 +154,22 @@
.toLocaleString('de-DE', { valute: 'EUR' })}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">
{(donation.paidAmount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
{#if donation.status =="PAID"}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">{$_('paid')}</span>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">{$_('open')}</span>
{/if}
</td>
{#if active_deletes[donation.id] === true}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
@@ -149,7 +187,7 @@
(obj) => obj.id !== donation.id
);
Toastify({
text: 'Donation deleted',
text: $_('donation-deleted'),
duration: 500,
backgroundColor:
'linear-gradient(to right, #00b09b, #96c93d)',
@@ -163,6 +201,9 @@
{:else}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
on:click={() => {open_payment_modal(donation);}}
class="text-[#025a21] hover:text-green-900 mr-4">{$_('enter-payment')}</button>
<a
href="./{donation.id}"
class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a>

View File

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

View File

@@ -193,6 +193,12 @@
<span>{(editable.donationAmount / 100)
.toFixed(2)
.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 />
<span class="font-medium text-gray-700">{$_('donations')}:</span>
{#if current_donations.filter((d) => d.donor.id == editable.id).length > 0}

View File

@@ -20,6 +20,31 @@
{$_('add-donor')}
</button>
{/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>
<DonorsOverview bind:current_donors />
</section>

View File

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

View File

@@ -32,8 +32,12 @@
target="_blank"
rel="noopener, noreferrer"
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>
-

View File

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

View File

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

View File

@@ -9,11 +9,15 @@
import Toastify from "toastify-js";
import ConfirmOrgDeletion from "./ConfirmOrgDeletion.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
$: searchvalue = "";
$: active_deletes = [];
$: sponsoring_contracts_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);
$: certificates_show = current_organizations.some(
(r) => r.is_selected === true
);
export let current_organizations = [];
const promise = RunnerOrganizationService.runnerOrganizationControllerGetAll().then(
@@ -55,6 +59,9 @@
<GenerateRunnerCards
bind:cards_show
bind:generate_orgs />
<GenerateRunnerCertificates
bind:certificates_show
bind:generate_orgs />
</div>
<div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">

View File

@@ -41,7 +41,7 @@
duration: -1,
}).showToast();
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",
headers: {
@@ -67,7 +67,7 @@
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = "Runnercards.pdf";
a.download = `${$_('runnercards')}-${locale}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
@@ -101,7 +101,7 @@
cards.push(card);
}
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",
headers: {
@@ -127,7 +127,12 @@
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
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);
a.click();
a.remove();
@@ -149,7 +154,7 @@
}).showToast();
let count = 0;
const current_cards = await RunnerCardService.runnerCardControllerGetAll();
for await (const t of generate_teams) {
for (const t of generate_teams) {
const runners = await RunnerTeamService.runnerTeamControllerGetRunners(
t.id
);
@@ -164,7 +169,7 @@
cards.push(card);
}
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",
headers: {
@@ -191,7 +196,7 @@
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = "Sponsorings_" + t.name + ".pdf";
a.download = `${$_('runnercards')}_${t.name}-${locale}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
@@ -211,15 +216,16 @@
async function generateOrgCards(locale) {
const toast = Toastify({
text: $_("generating-pdf"),
text: $_("generating-pdfs"),
duration: -1,
}).showToast();
let count = 0;
const current_cards = await RunnerCardService.runnerCardControllerGetAll();
for await (const o of generate_orgs) {
const runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners(
o.id
);
let count = 0;
let count_orgs =0;
for (const o of generate_orgs) {
count_orgs++;
let count = 0;
let runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners(o.id, true)
let cards = [];
for (let runner of runners) {
let card = current_cards.find((c) => c.runner?.id == runner.id);
@@ -230,8 +236,8 @@
}
cards.push(card);
}
fetch(
`${config.baseurl}/documents/cards?locale=${locale}&download=true&key=${config.documentserver_key}`,
await fetch(
`${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`,
{
method: "POST",
headers: {
@@ -240,39 +246,97 @@
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) => {
count++;
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = "Sponsorings_" + o.name + ".pdf";
document.body.appendChild(a);
a.click();
a.remove();
if (count === generate_orgs.length) {
toast.hideToast();
Toastify({
text: $_("pdfs-successfully-generated"),
duration: 3500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
})
.catch((err) => {});
.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}_direct-${locale}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
if (count === o.teams.length && count_orgs === generate_orgs.length) {
toast.hideToast();
console.log("here")
Toastify({
text: $_("pdfs-successfully-generated"),
duration: 3500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
})
.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>

View File

@@ -0,0 +1,331 @@
<script>
import { _ } from "svelte-i18n";
import {
DonationService,
RunnerTeamService,
RunnerOrganizationService
} from "@odit/lfk-client-js";
import Toastify from "toastify-js";
export let certificates_show = false;
export let generate_runners = [];
export let generate_orgs = [];
export let generate_teams = [];
$: certificates_dropdown_open = false;
document.addEventListener("click", function (e) {
if (
e.target.parentNode?.parentNode?.id != "certificates:dropdown" &&
e.target.parentNode?.parentNode?.id != "certificates:dropdown:menu"
) {
certificates_dropdown_open = false;
}
});
function generateCertificates(locale) {
certificates_dropdown_open = false;
if (generate_orgs.length > 0) {
generateOrgCertificates(locale);
} else if (generate_teams.length > 0) {
generateTeamCertificates(locale);
} else {
generateRunnerCertificates(locale);
}
}
async function generateRunnerCertificates(locale) {
const toast = Toastify({
text: $_("generating-pdf"),
duration: -1,
}).showToast();
const current_donations = (await DonationService.donationControllerGetAll()) || [];
let certificateRunners = [];
for (let runner of generate_runners) {
runner.distanceDonations = current_donations.find((d) => d.runner?.id == runner.id) || [];
certificateRunners.push(runner);
}
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;
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);
a.click();
a.remove();
toast.hideToast();
Toastify({
text: $_("pdf-successfully-generated"),
duration: 3500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
})
.catch((err) => {});
}
async function generateTeamCertificates(locale) {
const toast = Toastify({
text: $_("generating-pdfs"),
duration: -1,
}).showToast();
let count = 0;
const current_donations = (await DonationService.donationControllerGetAll()) || [];
for (const t of generate_teams) {
const runners = await RunnerTeamService.runnerTeamControllerGetRunners(
t.id
);
let certificateRunners = [];
for (let runner of runners) {
runner.distanceDonations = current_donations.find((d) => d.runner?.id == runner.id) || [];
certificateRunners.push(runner);
}
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) => {
count++;
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = `${$_('certificates')}_${t.name}-${locale}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
if (count === generate_teams.length) {
toast.hideToast();
Toastify({
text: $_("pdfs-successfully-generated"),
duration: 3500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
})
.catch((err) => {});
}
}
async function generateOrgCertificates(locale) {
const toast = Toastify({
text: $_("generating-pdfs"),
duration: -1,
}).showToast();
const current_donations = (await DonationService.donationControllerGetAll()) || [];
let count = 0;
let count_orgs =0;
for (const o of generate_orgs) {
count_orgs++;
let count = 0;
let runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners(o.id, true)
let certificateRunners = [];
for (let runner of runners) {
runner.distanceDonations = current_donations.find((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}_direct-${locale}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
if (count === o.teams.length && count_orgs === generate_orgs.length) {
toast.hideToast();
console.log("here")
Toastify({
text: $_("pdfs-successfully-generated"),
duration: 3500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
})
.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.find((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>
{#if certificates_show}
<div id="certificates:dropdown" class="relative inline-block">
<div>
<button
on:click={() => {
certificates_dropdown_open = !certificates_dropdown_open;
}}
type="button"
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-600 text-base font-medium text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 sm:ml-3 sm:w-auto sm:text-sm inline-flex"
id="options-menu"
aria-haspopup="true"
aria-expanded="true">
{$_('generate-runner-certificates')}
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
class="-mr-1 ml-2 h-5 w-5"><path
fill="none"
d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M3 19h18v2H3v-2zm10-5.83l6.07-6.07 1.42 1.41L12 17 3.52 8.52l1.4-1.42L11 13.17V2h2v11.17z" /></svg>
</button>
</div>
{#if certificates_dropdown_open}
<div
class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5"
id="certificates:dropdown:menu">
<div
class="py-1"
role="menu"
aria-orientation="vertical"
aria-labelledby="options-menu">
<span
class="block w-full text-left px-4 py-2 text-sm text-gray-700">{$_('select-language')}</span>
<button
on:click={() => {
generateCertificates('de');
}}
type="submit"
class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900"
role="menuitem">
{$_('german')}
</button>
<button
on:click={() => {
generateCertificates('en');
}}
type="submit"
class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900"
role="menuitem">
{$_('english')}
</button>
</div>
</div>
{/if}
</div>
{/if}

View File

@@ -1,6 +1,9 @@
<script>
import { getLocaleFromNavigator, _ } from "svelte-i18n";
import { RunnerOrganizationService, RunnerTeamService } from "@odit/lfk-client-js";
import {
RunnerOrganizationService,
RunnerTeamService,
} from "@odit/lfk-client-js";
import Toastify from "toastify-js";
export let sponsoring_contracts_show = false;
export let generate_runners = [];
@@ -34,13 +37,13 @@
duration: -1,
}).showToast();
let count = 0;
for await (const t of generate_teams) {
for (const t of generate_teams) {
count++;
const runners = await RunnerTeamService.runnerTeamControllerGetRunners(
t.id
);
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",
headers: {
@@ -66,7 +69,7 @@
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = "Sponsorings_" + t.name + ".pdf";
a.download = `${$_('sponsorings')}_${t.name}-${locale}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
@@ -89,12 +92,13 @@
text: $_("generating-pdf"),
duration: -1,
}).showToast();
for await (const o of generate_orgs) {
const runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners(
o.id
);
fetch(
`${config.baseurl}/documents/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`,
let count_orgs =0;
for (const o of generate_orgs) {
count_orgs++;
let count = 0;
let runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners(o.id, true)
await fetch(
`${config.baseurl_documentserver}/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`,
{
method: "POST",
headers: {
@@ -103,39 +107,87 @@
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) => {
count++;
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = "Sponsorings_" + o.name + ".pdf";
document.body.appendChild(a);
a.click();
a.remove();
if (count === generate_orgs.length) {
toast.hideToast();
Toastify({
text: $_("pdfs-successfully-generated"),
duration: 3500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
})
.catch((err) => {});
.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}_direct-${locale}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
if (count === o.teams.length && count_orgs === generate_orgs.length) {
toast.hideToast();
console.log("here")
Toastify({
text: $_("pdfs-successfully-generated"),
duration: 3500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
})
.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) => {});
}
}
}
@@ -145,7 +197,7 @@
duration: -1,
}).showToast();
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",
headers: {
@@ -171,7 +223,10 @@
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
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);
a.click();
a.remove();

View File

@@ -34,7 +34,7 @@
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
import_modal_open = false;
cancelModal();
}
if (e.keyCode === 13) {
//
@@ -202,7 +202,7 @@
toast.hideToast();
recent_processed = true;
Toastify({
text: "Import finished",
text: $_('import-finished'),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
@@ -281,6 +281,16 @@
bind:files
type="file" />
</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 json_output.length > 0}
{#if opened_from === 'OrgOverview'}

View File

@@ -2,6 +2,7 @@
import { getLocaleFromNavigator, _ } from "svelte-i18n";
import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
import store from "../../store";
import {
RunnerService,
@@ -36,6 +37,7 @@
editable.group != null;
$: sponsoring_contracts_show = true;
$: cards_show = true;
$: certificates_show = true;
$: generate_runners = [original_data_pdf];
runner_promise.then((data) => {
data_loaded = true;
@@ -158,7 +160,10 @@
bind:sponsoring_contracts_show
bind:generate_runners />
<GenerateRunnerCards
bind:sponsoring_contracts_show
bind:cards_show
bind:generate_runners />
<GenerateRunnerCertificates
bind:certificates_show
bind:generate_runners />
{#if !delete_triggered}
<button

View File

@@ -10,6 +10,7 @@
import Select from "svelte-select";
import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
$: searchvalue = "";
$: active_deletes = [];
export let current_runners = [];
@@ -27,6 +28,9 @@
$: cards_show = current_runners.some(
(r) => r.is_selected === true
);
$: certificates_show = current_runners.some(
(r) => r.is_selected === true
);
$: generate_runners = current_runners.filter((r) => r.is_selected === true);
$: teams = [];
$: orgs = [];
@@ -92,6 +96,9 @@
<GenerateRunnerCards
bind:cards_show
bind:generate_runners />
<GenerateRunnerCertificates
bind:certificates_show
bind:generate_runners />
</div>
<div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
@@ -190,7 +197,7 @@
{#if runner.group.responseType === 'RUNNERTEAM'}
<a
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 runner.group.responseType === 'RUNNERORGANIZATION'}
<a

View File

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

View File

@@ -4,6 +4,9 @@
import { MeService } from "@odit/lfk-client-js";
import Toastify from "toastify-js";
import ConfirmProfileDeletion from "./ConfirmProfileDeletion.svelte";
import PasswordStrength, {
password_strong_enough_and_equal,
} from "../auth/PasswordStrength.svelte";
$: data_loaded = false;
$: delete_triggered = false;
$: original_data = {};
@@ -15,8 +18,10 @@
JSON.stringify(editable) === JSON.stringify(original_data)
);
$: save_enabled = changes_performed && isEmail(editable.email);
$: update_password_enabled =
password_change.length > 0 && password_change === password_confirm;
$: update_password_enabled = password_strong_enough_and_equal(
password_change,
password_confirm
);
const user_promise = MeService.meControllerGet().then((data) => {
data_loaded = true;
data.groups = data.groups.map((g) => g.id);
@@ -45,7 +50,7 @@
function changePassword() {
if (data_loaded === true && update_password_enabled) {
Toastify({
text: $_('changing-your-password'),
text: $_("changing-your-password"),
duration: 2500,
}).showToast();
let postdata = Object.assign({}, original_data);
@@ -56,7 +61,7 @@
password_change = "";
postdata = {};
Toastify({
text: $_('password-changed'),
text: $_("password-changed"),
duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
@@ -242,10 +247,7 @@
class="border-gray-300 placeholder-gray-500 appearance-none rounded-md relative block w-full px-3 py-2 border focus:outline-none focus:shadow-outline-blue focus:border-blue-300 focus:z-10 sm:text-sm"
placeholder={$_('password')} />
</div>
{#if password_change != password_confirm && password_change.length > 0}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">{$_('passwords-dont-match')}</span>
{/if}
<PasswordStrength bind:password_change bind:password_confirm />
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button
@@ -257,9 +259,9 @@
{$_('update-password')}
</button>
{#if update_password_enabled}
<p>
{$_('after-the-update-youll-get-logged-out-please-login-with-your-new-password-after-that')}
</p>
<p>
{$_('after-the-update-youll-get-logged-out-please-login-with-your-new-password-after-that')}
</p>
{/if}
</div>
</div>

View File

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

View File

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

View File

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

View File

@@ -9,6 +9,7 @@
import { clickOutside } from "../base/outsideclick";
import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
$: searchvalue = "";
$: active_deletes = [];
$: sponsoring_contracts_show = current_teams.some(
@@ -17,6 +18,9 @@
$: cards_show = current_teams.some(
(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);
export let current_teams = [];
let modal_open = false;
@@ -61,6 +65,9 @@
<GenerateRunnerCards
bind:cards_show
bind:generate_teams />
<GenerateRunnerCertificates
bind:certificates_show
bind:generate_teams />
</div>
<div
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}"]`
).parentNode.parentNode.parentNode;
Toastify({
text: "Track is being updated...",
text: $_('track-is-being-updated'),
duration: 500,
}).showToast();
TrackService.trackControllerPut(trackid, {
@@ -45,7 +45,7 @@
})
.then((r) => {
Toastify({
text: "Track was updated!",
text: $_('track-was-updated'),
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
duration: 1000,
}).showToast();

View File

@@ -5,6 +5,9 @@
import { UserService } from "@odit/lfk-client-js";
import isEmail from "validator/es/lib/isEmail";
import Toastify from "toastify-js";
import PasswordStrength, {
password_strong_enough,
} from "../auth/PasswordStrength.svelte";
export let modal_open;
export let current_users;
let firstname_input;
@@ -28,7 +31,10 @@
$: isLastnameValid = lastname_input_value.trim().length !== 0;
$: isFirstnameValid = firstname_input_value.trim().length !== 0;
$: createbtnenabled =
isFirstnameValid && isLastnameValid && isPasswordValid && isEmailValid;
isFirstnameValid &&
isLastnameValid &&
password_strong_enough(password_input_value) &&
isEmailValid;
(function () {
document.onkeydown = function (e) {
e = e || window.event;
@@ -203,12 +209,8 @@
type="password"
name="password"
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !isPasswordValid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
{$_('password-is-required')}
</span>
{/if}
<PasswordStrength
bind:password_change={password_input_value} />
</div>
<div class="col-span-6">
<label

View File

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

View File

@@ -1,14 +0,0 @@
import App from './App.svelte';
const app = new App({
target: document.body
});
export default app;
// HMR
if (import.meta.hot) {
import.meta.hot.accept();
import.meta.hot.dispose(() => {
app.$destroy();
});
}

View File

@@ -22,6 +22,7 @@
"add-your-fist-donation": "Erstelle dein erstes Sponsoring",
"add-your-fist-scan": "Füge deinen ersten Scan hinzu",
"adding-card": "Karte wird erstellt",
"adding-donation": "Sponsoring wird erstellt...",
"adding-scan": "Scan wird hinzugefügt",
"address": "Adresse",
"address-is-required": "Du musst eine Adresse angeben",
@@ -30,6 +31,7 @@
"all-associated-donations-will-get-deleted-as-well": "Alle Sponsorings dieser Sponsor:in werden ebenfalls gelöscht",
"all-associated-runners-will-be-deleted-too": "Alle zugehörigen Läufer:innen werden auch gelöscht!",
"all-associated-teams-and-runners-will-be-deleted-too": "Alle assoziierten Teams und Läufer:innen werden auch gelöscht!",
"already-paid": "Bereits bezahlt",
"amount": "Anzahl",
"amount-per-kilometer": "Betrag pro Kilometer",
"apartment-suite-etc": "Apartment, Wohnung, etc.",
@@ -50,6 +52,7 @@
"card-deleted": "Karte gelöscht",
"card-updated": "Karte aktualisiert",
"cards": "Läuferkarten",
"certificates": "Urkunden",
"change-your-password-here": "Hier kannst du dein Passwort ändern",
"changing-your-password": "Passwort wird geändert",
"city": "Stadt",
@@ -67,8 +70,10 @@
"confirm-deletion": "Löschung Bestätigen",
"confirm-the-new-password": "Neues Passwort bestätigen",
"contact": "Kontakt",
"contact-added": "Kontakt wurde hinzugefügt",
"contact-deleted": "Kontakt gelöscht",
"contact-information": "Kontaktinformation",
"contact-is-being-added": "Kontakt wird erstellt...",
"contact-is-being-updated": "Kontakt wird aktualisiert ...",
"contact-is-not-a-member-in-any-group": "Kontakt gehört zu keiner Gruppe",
"contacts": "Kontakte",
@@ -92,12 +97,14 @@
"create-a-new-track": "Neuen Track erstellen",
"create-a-new-user": "Neue Benutzer:in anlegen",
"create-a-new-user-group": "Erstelle eine neue Gruppe",
"create-and-generate-pdf": "Erstellen und PDF herunterladen",
"create-bulk-blanco-cards": "Blankokarten erstellen",
"create-bulk-cards": "Blankokarten erstellen",
"create-organization": "Organisation erstellen",
"create-team": "Team erstellen",
"create-track": "Track erstellen",
"create-user": "Benutzer anlegen",
"create-without-pdf": "Ohne PDF erstellen",
"created-blanco-cards": "Blankokarten wurden erstellt",
"creating-blanco-cards": "Erstelle Blankokarten",
"credits": "Credits",
@@ -126,7 +133,7 @@
},
"delete": "Löschen",
"delete-contact": "Kontakt löschen",
"delete-donation": "Sponsporing löschen",
"delete-donation": "Sponsoring löschen",
"delete-donor": "Sponsor:in löschen",
"delete-group": "Gruppe löschen",
"delete-organization": "Organisation löschen",
@@ -154,6 +161,9 @@
"documentation": "Dokumentation",
"donation-amount": "Sponsoringbetrag",
"donation-amount-must-be-greater-that-0-00eur": "Der Sponsoringbetrag muss größer als 0.00€ sein.",
"donation-deleted": "Sponsoring gelöscht",
"donation-updated": "Sponsoring wurde aktualisiert",
"donation_added": "Sponsoring hinzugefügt",
"donations": "Sponsorings",
"donor": "Sponsor:in",
"donor-added": "Sponsor:in hinzugefügt",
@@ -173,6 +183,7 @@
"enabled": "aktiviert",
"enabled_large": "Aktiviert",
"english": "Englisch",
"enter-payment": "Zahlung eingeben",
"error-during-import": "Fehler beim Importieren",
"error-whyile-copying-to-clipboard": "Fehler beim Kopieren in die Zwischenablage",
"error_on_login": "😢Fehler beim Login",
@@ -180,6 +191,7 @@
"everything-concerning-your-profile": "Alles zu deinem Profil",
"everything-is-more-fun-together": "Im Team macht's mehr Spaß 🏃‍♂️🏃‍♀️🏃‍♂️",
"faq": "FAQ",
"filename_sponsoringquittungsliste": "SponsoringQuittungsListe",
"filter-by-organization-team": "Filtern nach Organisation / Team",
"first-name": "Vorname",
"first-name-is-required": "Vorname muss angegeben werden",
@@ -189,10 +201,12 @@
"geerbte": "geerbte",
"general-stats": "Allgemeine Statistiken",
"general_promise_error": "😢 Ein unbekannter Fehler ist aufgetreten",
"generate-runner-certificate": "Urkunde generieren",
"generate-runner-certificates": "Urkunden generieren",
"generate-runnercards": "Läuferkarten generieren",
"generate-sponsoring-contract": "Sponsoringvertrag generieren",
"generate-sponsoring-contracts": "Sponsoringverträge generieren",
"generating-pdf": "Pdf wird generiert...",
"generating-pdf": "PDF wird generiert...",
"generating-pdfs": "PDFs werden generiert...",
"generic-ui-logic-error": "Etwas ist in der Benutzeroberfläche schiefgelaufen.",
"german": "Deutsch",
@@ -245,6 +259,10 @@
"middle-name": "Mittelname",
"minimum-lap-time-in-s": "Minimale Rundenzeit (in Sekunden)",
"minimum-lap-time-must-be-a-positive-number-or-0": "Die minimale Rundenzeit muss eine positive Zahl oder 0 sein",
"must-be-at-least-10-characters-long": "Passwort muss mindestens 10 Zeichen lang sein!",
"must-contain-a-lowercase-letter": "Passwort muss einen Großbuchstaben enthalten!",
"must-contain-a-number": "Passwort muss eine Zahl enthalten!",
"must-contain-a-uppercase-letter": "Passwort muss einen Kleinbuchstaben enthalten!",
"name": "Name",
"name-is-required": "Der Gruppenname muss angegeben werden",
"new-password": "Neues Passwort",
@@ -259,6 +277,7 @@
"no-runners-found": "Keine Läufer:innen gefunden",
"no-tracks-added-yet": "Es wurden noch keine Tracks erstellt.",
"non-blanko": "Keine/Blankokarte",
"open": "OFFEN",
"organization": "Organisation",
"organization-added": "Organisation hinzugefügt",
"organization-deleted": "Organisation gelöscht",
@@ -269,6 +288,8 @@
"organizations-are-being-loaded": "Organisationen werden geladen ...",
"orgs": "Organisationen",
"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!",
"paid": "BEZAHLT",
"paid-amount": "Gezahlter Betrag",
"password": "Passwort",
"password-changed": "Passwort wurde aktualisiert!",
"password-is-required": "Passwort muss angegeben werden",
@@ -276,7 +297,8 @@
"password-reset-in-progress": "Passwort wird zurückgesetzt...",
"password-reset-mail-sent": "Passwort-Reset Mail wurde an \"{usersEmail}\" geschickt.",
"password-reset-successful": "Passwort erfolgreich zurückgesetzt!",
"passwords-dont-match": "Die Passwörter stimmen nicht überein.",
"passwords-dont-match": "Die Passwörter stimmen nicht überein!",
"payment-amount-must-be-greater-than-0-00eur": "Der Zahlungsbetrag muss größer als 0.00€ sein!",
"pdf-generation-failed": "PDF Generierung fehlgeschlagen!",
"pdf-successfully-generated": "PDF wurde erfolgreich generiert!",
"pdfs-successfully-generated": "Alle PDFs wurden generiert!",
@@ -299,9 +321,11 @@
"please-provide-the-required-information-to-add-a-new-user": "Bitte gebe alle nötigen Informationen an, im die neue Benutzer:in zu erstellen.",
"please-provide-the-required-information-to-create-a-new-scanstation": "Bitte gebe alle für eine Scannerstation notwendigen Informationen an",
"please-request-a-new-reset-mail": "Bitte eine neue Passwortreset-Mail anfordern...",
"please-wait-a-moment-your-login-is-still-being-processed": "Bitte warte einen Moment, deine Anmeldung wird verarbeitet",
"privacy": "Datenschutz",
"privacy-loading": "Datenschutzerklärung lädt...",
"profile": "Profil",
"profile-deleted": "Profil gelöscht!",
"profile-picture": "Profilbild",
"profile-updated": "Profil wurde aktualisiert!",
"read-license": "Lizenz-Text lesen",
@@ -315,6 +339,7 @@
"runner-import": "Läufer:innen Import",
"runner-is-being-added": "Läufer:in wird hinzugefügt...",
"runner-updated": "Läufer:in aktualisiert!",
"runnercards": "Laeuferkarten",
"runnerimport_verify_runners_org": "Bitte die Läufer:innen für den Import in die Organisation \"{org_name}\" bestätigen",
"runners": "Läufer",
"runners-are-being-imported": "Läufer:innen werden importiert ...",
@@ -344,12 +369,17 @@
"settings": "Einstellungen",
"settings-for-your-profile": "Die Einstellungen deines Accounts",
"something-about-the-group": "Infos zur Gruppe",
"sponsoring-quittungs-liste_herunterladen": "Sponsoring-Quittungs-Liste herunterladen",
"sponsorings": "Sponsoringerklaerungen",
"stats-are-being-loaded": "Die Statistiken werden geladen...",
"status": "Status",
"stuff-that-could-harm-your-profile": "Einstellungen, die deinem Profil nachhaltig schaden können",
"successful-password-reset": "Passwort erfolgreich zurückgesetzt!",
"team": "Team",
"team-added": "Team wurde hinzugefügt",
"team-deleted": "Team gelöscht",
"team-detail-is-being-loaded": "Team wird geladen...",
"team-is-being-added": "Team wird erstellt...",
"team-name": "Teamname",
"team-name-is-required": "Teamname ist erforderlich",
"teams": "Teams",
@@ -374,26 +404,35 @@
"total-distance": "gelaufene Strecke",
"total-donation-amount": "Gesamtbetrag",
"total-donations": "Spendensumme",
"total-paid-amount": "Gezahlter Gesamtbetrag",
"total-scans": "gesamte Scans",
"total_donation_amount_in_eur": "Gesamtbetrag in €",
"track": "Track",
"track-added": "Track hinzugefügt",
"track-data-is-being-loaded": "Trackdaten werden geladen",
"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",
@@ -411,6 +450,7 @@
"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-scanstations-yet": "Es gibt noch keine Scannerstationen",

View File

@@ -6,7 +6,8 @@
"active": "Active",
"add-card": "Add Card",
"add-donation": "Add donation",
"add-donor": "add donor",
"add-donor": "Add donor",
"add-or-update-a-payment": "Add or update a payment",
"add-scan": "Add scan",
"add-the-first-scanstation": "Add your first scanstation.",
"add-user-group": "Add User Group",
@@ -22,6 +23,7 @@
"add-your-fist-donation": "Add your fist donation",
"add-your-fist-scan": "Add your fist scan",
"adding-card": "Adding Card",
"adding-donation": "Adding donation...",
"adding-scan": "Adding Scan",
"address": "Address",
"address-is-required": "Address is required",
@@ -30,6 +32,7 @@
"all-associated-donations-will-get-deleted-as-well": "All associated donations will get deleted as well",
"all-associated-runners-will-be-deleted-too": "All associated runners will be deleted too!",
"all-associated-teams-and-runners-will-be-deleted-too": "All associated teams and runners will be deleted too!",
"already-paid": "Already paid",
"amount": "Amount",
"amount-per-kilometer": "Amount per kilometer",
"apartment-suite-etc": "Apartment, suite, etc.",
@@ -50,6 +53,7 @@
"card-deleted": "Card deleted",
"card-updated": "Card updated",
"cards": "Cards",
"certificates": "Certificates",
"change-your-password-here": "Change your password here",
"changing-your-password": "Changing your password",
"city": "City",
@@ -67,8 +71,10 @@
"confirm-deletion": "Confirm Deletion",
"confirm-the-new-password": "Confirm the new password",
"contact": "Contact",
"contact-added": "Contact added",
"contact-deleted": "Contact deleted",
"contact-information": "Contact Information",
"contact-is-being-added": "Contact is being added...",
"contact-is-being-updated": "Contact is being updated...",
"contact-is-not-a-member-in-any-group": "Contact is not a member in any group",
"contacts": "Contacts",
@@ -92,12 +98,14 @@
"create-a-new-track": "Create a new Track",
"create-a-new-user": "Create a new User",
"create-a-new-user-group": "Create a new user group",
"create-and-generate-pdf": "Create and generate PDF",
"create-bulk-blanco-cards": "Create bulk blanco cards",
"create-bulk-cards": "Add blanco cards",
"create-organization": "Create Organization",
"create-team": "Create Team",
"create-track": "Create Track",
"create-user": "Create User",
"create-without-pdf": "Create without PDF",
"created-blanco-cards": "Created blanco cards",
"creating-blanco-cards": "Creating blanco cards",
"credits": "Credits",
@@ -154,6 +162,9 @@
"documentation": "Documentation",
"donation-amount": "Donation amount",
"donation-amount-must-be-greater-that-0-00eur": "Donation amount must be greater that 0.00€",
"donation-deleted": "Donation deleted",
"donation-updated": "Donation updated",
"donation_added": "Donation_added",
"donations": "Donations",
"donor": "Donor",
"donor-added": "Donor added",
@@ -173,6 +184,7 @@
"enabled": "enabled",
"enabled_large": "Enabled",
"english": "English",
"enter-payment": "Enter payment",
"error-during-import": "Error during import",
"error-whyile-copying-to-clipboard": "Error while copying to clipboard",
"error_on_login": "Error on login",
@@ -180,6 +192,7 @@
"everything-concerning-your-profile": "Everything concerning your profile",
"everything-is-more-fun-together": "everything is more fun together 🏃‍♂️🏃‍♀️🏃‍♂️",
"faq": "FAQ",
"filename_sponsoringquittungsliste": "DonorReceiptList",
"filter-by-organization-team": "Filter by Organization/ Team",
"first-name": "First name",
"first-name-is-required": "First Name is required",
@@ -189,6 +202,8 @@
"geerbte": "inherited",
"general-stats": "General Stats",
"general_promise_error": "😢 Error",
"generate-runner-certificate": "Generate runner certificate",
"generate-runner-certificates": "Generate runner certificates",
"generate-runnercards": "Generate Runnercards",
"generate-sponsoring-contract": "generate sponsoring contract",
"generate-sponsoring-contracts": "generate sponsoring contracts",
@@ -245,6 +260,10 @@
"middle-name": "Middle name",
"minimum-lap-time-in-s": "minimum lap time in s",
"minimum-lap-time-must-be-a-positive-number-or-0": "minimum lap time must be a positive number or 0",
"must-be-at-least-10-characters-long": "Must be at least 10 characters long!",
"must-contain-a-lowercase-letter": "Must contain a lowercase letter!",
"must-contain-a-number": "Must contain a number!",
"must-contain-a-uppercase-letter": "Must contain a uppercase letter!",
"name": "Name",
"name-is-required": "Name is required",
"new-password": "New password",
@@ -259,6 +278,7 @@
"no-runners-found": "No runners found",
"no-tracks-added-yet": "there are no tracks added yet.",
"non-blanko": "Non/Blanko",
"open": "OPEN",
"organization": "Organization",
"organization-added": "Organization added",
"organization-deleted": "Organization deleted",
@@ -269,6 +289,8 @@
"organizations-are-being-loaded": "organizations are being loaded...",
"orgs": "Organizations",
"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!",
"paid": "PAID",
"paid-amount": "Paid amount",
"password": "Password",
"password-changed": "Password changed!",
"password-is-required": "Password is required",
@@ -276,7 +298,8 @@
"password-reset-in-progress": "Password Reset in Progress...",
"password-reset-mail-sent": "Password reset mail was sent to \"{usersEmail}\".",
"password-reset-successful": "Password Reset successful!",
"passwords-dont-match": "Passwords don't match",
"passwords-dont-match": "Passwords don't match!",
"payment-amount-must-be-greater-than-0-00eur": "Payment amount must be greater than 0.00€!",
"pdf-generation-failed": "PDF generation failed!",
"pdf-successfully-generated": "PDF successfully generated!",
"pdfs-successfully-generated": "PDFs successfully generated!",
@@ -299,9 +322,11 @@
"please-provide-the-required-information-to-add-a-new-user": "Please provide the required information to add a new user.",
"please-provide-the-required-information-to-create-a-new-scanstation": "Please provide the required information to create a new scanstation",
"please-request-a-new-reset-mail": "Please request a new reset mail...",
"please-wait-a-moment-your-login-is-still-being-processed": "Please wait a moment, your login is still being processed",
"privacy": "Privacy",
"privacy-loading": "Privacy loading...",
"profile": "Profile",
"profile-deleted": "Profile deleted!",
"profile-picture": "Profile Picture",
"profile-updated": "Profile updated!",
"read-license": "Read License",
@@ -315,6 +340,7 @@
"runner-import": "Runner Import",
"runner-is-being-added": "Runner is being added...",
"runner-updated": "Runner updated!",
"runnercards": "Runnercards",
"runnerimport_verify_runners_org": "Please confirm these runners for import into the organization \"{org_name}\"",
"runners": "Runners",
"runners-are-being-imported": "Runners are being imported...",
@@ -344,12 +370,17 @@
"settings": "Settings",
"settings-for-your-profile": "Settings for your profile",
"something-about-the-group": "Something about the group...",
"sponsoring-quittungs-liste_herunterladen": "Download donor receipt list",
"sponsorings": "Sponsorings",
"stats-are-being-loaded": "stats are being loaded...",
"status": "Status",
"stuff-that-could-harm-your-profile": "Stuff that could harm your profile",
"successful-password-reset": "Successful password reset!",
"team": "Team",
"team-added": "Team added",
"team-deleted": "Team deleted",
"team-detail-is-being-loaded": "team detail is being loaded...",
"team-is-being-added": "Team is being added...",
"team-name": "Team name",
"team-name-is-required": "team name is required",
"teams": "Teams",
@@ -374,27 +405,35 @@
"total-distance": "total distance",
"total-donation-amount": "total donation amount",
"total-donations": "total donations",
"total-paid-amount": "Total paid amount",
"total-scans": "total scans",
"total_donation_amount_in_eur": "Total donation amount in €",
"track": "Track",
"track-added": "Track added",
"track-data-is-being-loaded": "Track data is being loaded",
"track-is-being-added": "Track is being added...",
"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",
@@ -412,6 +451,7 @@
"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-scanstations-yet": "You don't have any scanstations yet",

9
src/main.js Normal file
View File

@@ -0,0 +1,9 @@
import './style.css';
import "toastify-js/src/toastify.css";
import "gridjs/dist/theme/mermaid.css";
import App from './App.svelte';
const app = new App({
target: document.body
});
export default app;

3
src/style.css Normal file
View File

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

View File

@@ -1,14 +0,0 @@
export const register = () => {
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').then(
(registration) => {
// console.log(`sw successful with scope: ${registration.scope}`);
},
(err) => {
// console.log(`sw failed: ${err}`);
}
);
});
}
};

View File

@@ -1,14 +1,15 @@
module.exports = {
purge: {
content: [ './src/**/*.svelte' ]
},
// darkMode: 'media',
variants: {},
plugins: [],
mode: 'jit',
purge: [ './src/**/*.svelte' ],
theme: {
container: {
center: true,
padding: '1.5rem'
extend: {
colors: {
reepolee: {
500: '#b40000',
600: '#9c0000',
700: '#750000'
}
}
}
}
};

View File

@@ -1,19 +0,0 @@
const fs = require('fs');
let content_svelteconfig = fs.readFileSync('./s-config.template.js', { encoding: 'utf8' });
let content_html = fs.readFileSync('./index.template.html', { encoding: 'utf8' });
if (process.env.NODE_ENV_ODIT == 'development_fast') {
content_html = content_html.replace(
'__TAILWIND_INSERT__',
'<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss@2.0.2/dist/tailwind.min.css">'
);
content_svelteconfig = content_svelteconfig.replace('__insert__', '{postcss:{}}');
} else {
content_html = content_html.replace('__TAILWIND_INSERT__', '');
content_svelteconfig = content_svelteconfig.replace(
'__insert__',
"{postcss:{plugins:[require('tailwindcss'),require('autoprefixer')]}}"
);
}
fs.writeFileSync('./public/index.html', content_html);
fs.writeFileSync('./svelte.config.js', content_svelteconfig);
console.info('dev setup script done');

View File

@@ -1,5 +1,5 @@
const fs = require('fs');
const package = JSON.parse(fs.readFileSync(`./package.json`, { encoding: 'utf-8' }));
const original = fs.readFileSync(`./index.template.html`, { encoding: 'utf-8' });
const original = fs.readFileSync(`./index.html`, { encoding: 'utf-8' });
let out = original.replace(/RELEASE_INFO-(\S)+-RELEASE_INFO/gi, 'RELEASE_INFO-' + package.version + '-RELEASE_INFO');
fs.writeFileSync(`./index.template.html`, out);
fs.writeFileSync(`./index.html`, out);

38
vite.config.js Normal file
View File

@@ -0,0 +1,38 @@
import svelte from '@sveltejs/vite-plugin-svelte';
import { minify } from 'html-minifier';
import { defineConfig } from 'vite';
//
const indexReplace = () => {
return {
name: 'html-transform',
transformIndexHtml(html) {
return minify(html, {
collapseWhitespace: true
});
}
};
};
export default defineConfig(({ command, mode }) => {
const isProduction = mode === 'production';
return {
// base: './',
build: {
polyfillDynamicImport: false,
cssCodeSplit: false,
minify: isProduction
},
plugins: [
svelte({
//@ts-ignore
hot: !isProduction,
emitCss: true,
extensions: [ '.md', '.svx', '.svelte' ],
preprocess: [
//
]
}),
indexReplace()
]
};
});

View File

@@ -1,9 +0,0 @@
module.exports = {
globDirectory: 'public',
globPatterns: [ '**/*.{js,ico,png,svg,html,webmanifest,txt,json}' ],
globIgnores: [ 'env.js', 'env.sample.js' ],
swDest: 'public/sw.js',
cleanupOutdatedCaches: true,
mode: 'production',
sourcemap: false
};