Compare commits
	
		
			70 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 67c3732fad | |||
| 2932f4591e | |||
| df53c07450 | |||
| 40899e9d80 | |||
| f794af0950 | |||
| 1665a1a093 | |||
| 4a36fb6d95 | |||
| acf78a8822 | |||
| f5c1ec9939 | |||
| 4b3d38b05b | |||
| 23e0b53107 | |||
| c907486c4d | |||
| 6b5945add8 | |||
| 55693de934 | |||
| d467475b6d | |||
| 44bc14820f | |||
| ec447e2e36 | |||
| 0af2647965 | |||
| 08442154f4 | |||
| 9f7d2234fb | |||
| ddd82a71a7 | |||
| 014ba3bf67 | |||
| c87321f804 | |||
| 8b451b3c67 | |||
| 0cfc87fbe6 | |||
| ae9673070c | |||
| 1a52aaf8d1 | |||
| d6c315ab8e | |||
| 983ce56048 | |||
| de2fe0e9f1 | |||
| c3c95bf291 | |||
| d2050b5948 | |||
| 6b92405bae | |||
| 49e87ccb15 | |||
| 50fffef13b | |||
| 82b1811971 | |||
| aeadef60bb | |||
| a1ab65a0e9 | |||
| 17e0805fe6 | |||
| ddd9c396b6 | |||
| ef49e507c1 | |||
| fbe74a5d80 | |||
| 076893981f | |||
| fac059f02c | |||
| 0313f8cc49 | |||
| 7ad6b73574 | |||
| 3cd0468b19 | |||
| f46ccb610e | |||
| 8a32569a3b | |||
| 535b23ae91 | |||
| 4715978f81 | |||
| a516aa7775 | |||
| 77e9c205f9 | |||
| e852305400 | |||
| c6a15264b3 | |||
| 2d0beaaaad | |||
| 5c5ef95d2b | |||
| e838e6f321 | |||
| ca983c72d4 | |||
| 91dd5256e9 | |||
| 3d4dc2d72b | |||
| ba3471068a | |||
| 5a7b2cf886 | |||
| cc926e84fb | |||
| fff16e6650 | |||
| d6f6d10cb6 | |||
| 1249904582 | |||
| 8e0437728b | |||
| fb0c0718e4 | |||
| aa8196db3a | 
							
								
								
									
										101
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -2,9 +2,110 @@ | |||||||
|  |  | ||||||
| All notable changes to this project will be documented in this file. Dates are displayed in UTC. | All notable changes to this project will be documented in this file. Dates are displayed in UTC. | ||||||
|  |  | ||||||
|  | #### [0.9.0](https://git.odit.services/lfk/frontend/compare/0.8.7...0.9.0) | ||||||
|  |  | ||||||
|  | - Merge pull request 'Runner cards feature/94-runnercard_mgnt' (#111) from feature/94-runnercard_mgnt into dev [`2932f45`](https://git.odit.services/lfk/frontend/commit/2932f4591e62187a4903511051d110e9679c0993) | ||||||
|  | - Sorted translations 🌍 [`1665a1a`](https://git.odit.services/lfk/frontend/commit/1665a1a093862a13be78ec65dcdf64eb7d855593) | ||||||
|  | - Added translations [`6b5945a`](https://git.odit.services/lfk/frontend/commit/6b5945add86a77630c500872545bb91724b2047f) | ||||||
|  | - Sorted translations 🌍 [`d6c315a`](https://git.odit.services/lfk/frontend/commit/d6c315ab8e020bc65b967e2c3f4cd921392d66d5) | ||||||
|  | - Sorted translations [`de2fe0e`](https://git.odit.services/lfk/frontend/commit/de2fe0e9f171efb3deeea8cfe638f60e3ca90423) | ||||||
|  | - Added basic cards page [`5c5ef95`](https://git.odit.services/lfk/frontend/commit/5c5ef95d2be65c0e951dcd472113c8ce0593c9e0) | ||||||
|  | - Moved contract generation to it's own component [`0cfc87f`](https://git.odit.services/lfk/frontend/commit/0cfc87fbe6adfacab5c2fab732866aead3231fbf) | ||||||
|  | - Teams now use the new sponsoring contracts module [`014ba3b`](https://git.odit.services/lfk/frontend/commit/014ba3bf6718ff28f35c67c8f732b53aae50723c) | ||||||
|  | - Basic card generation worX 🎉🎉 [`d467475`](https://git.odit.services/lfk/frontend/commit/d467475b6d61d50bec3a043ea8792533e8593df6) | ||||||
|  | - Orgs now use the new sponsoring contracts module [`8b451b3`](https://git.odit.services/lfk/frontend/commit/8b451b3c6794e7df09898a687533ce8fadd56192) | ||||||
|  | - Added runnercard detail/edit modal [`0313f8c`](https://git.odit.services/lfk/frontend/commit/0313f8cc495088df1237d00e6b9ed1a94f019644) | ||||||
|  | - Implemented Add card modal [`535b23a`](https://git.odit.services/lfk/frontend/commit/535b23ae917de154e08962f5d486c50d6e091fe0) | ||||||
|  | - Added bulk card creation modal [`8a32569`](https://git.odit.services/lfk/frontend/commit/8a32569a3be1ad26ba163f4e2b67a368cfeeb422) | ||||||
|  | - Added basic card overview [`c6a1526`](https://git.odit.services/lfk/frontend/commit/c6a15264b3d13d516f3d97ea4b891ed1c328cead) | ||||||
|  | - Fixed org generation not hiding the generation toast [`c87321f`](https://git.odit.services/lfk/frontend/commit/c87321f804858f84fcccd85a15b9c3fb003c18be) | ||||||
|  | - Working runner runnercard generation [`c907486`](https://git.odit.services/lfk/frontend/commit/c907486c4d1c64114124deb3cd0d0cf11d38a6b1) | ||||||
|  | - Implemented bulk creation [`7ad6b73`](https://git.odit.services/lfk/frontend/commit/7ad6b73574174f24f2d6f23b3caf4823881a85e7) | ||||||
|  | - Now w/ working dialog🎉🎉🎉 [`ae96730`](https://git.odit.services/lfk/frontend/commit/ae9673070c3959ff6190a37123f3fc609b182c5a) | ||||||
|  | - Now w/working editing [`fac059f`](https://git.odit.services/lfk/frontend/commit/fac059f02cae84261443ee95448ec8db06dd755a) | ||||||
|  | - Added runnercard generation for teams [`23e0b53`](https://git.odit.services/lfk/frontend/commit/23e0b53107623c505d07a99a51ce836c9324acce) | ||||||
|  | - Added bulk creation modal to cards view [`f46ccb6`](https://git.odit.services/lfk/frontend/commit/f46ccb610e01654a4ee5e47d78ab500045dd494b) | ||||||
|  | - Added a new runenrcard logo [`acf78a8`](https://git.odit.services/lfk/frontend/commit/acf78a88221d0988f6501ae341e028a4113b578d) | ||||||
|  | - Moved modal import to overview for simplification [`1a52aaf`](https://git.odit.services/lfk/frontend/commit/1a52aaf8d1ad19b03d355aec0e1c48182db024f9) | ||||||
|  | - Added CardsEmptyState + Emtystate graphic [`2d0beaa`](https://git.odit.services/lfk/frontend/commit/2d0beaaaad4efefd036bbef09f10c8c22bdb2760) | ||||||
|  | - Added message for missing runner/blanco card) [`4715978`](https://git.odit.services/lfk/frontend/commit/4715978f810bbb283876f06d147b1ec86d373786) | ||||||
|  | - Fixed counting bug [`f5c1ec9`](https://git.odit.services/lfk/frontend/commit/f5c1ec9939d856804c9ec3ead4b3ed869fc2ea63) | ||||||
|  | - Added card generation/printing from detail [`4a36fb6`](https://git.odit.services/lfk/frontend/commit/4a36fb6d952d9fe4d5edbe1ed0779c7fbcd50ef0) | ||||||
|  | - Formatting [`a516aa7`](https://git.odit.services/lfk/frontend/commit/a516aa7775faa2244862bb2e3c4de623c6405e5b) | ||||||
|  | - Moved the pdf generation related componenets to their own folder [`ddd82a7`](https://git.odit.services/lfk/frontend/commit/ddd82a71a7b67ead892626addfd56ba4cc632750) | ||||||
|  | - Now routing the cards page [`e852305`](https://git.odit.services/lfk/frontend/commit/e852305400a139f8169350077c30012aed556828) | ||||||
|  | - Fuggin snowpack bs [`44bc148`](https://git.odit.services/lfk/frontend/commit/44bc14820fed26d5e0d8b12ecd6b46ca0608ae7b) | ||||||
|  | - Formatting [`9f7d223`](https://git.odit.services/lfk/frontend/commit/9f7d2234fb9603a7391ec9a64253724c2c25c333) | ||||||
|  | - Now with working org runenrcard generation [`4b3d38b`](https://git.odit.services/lfk/frontend/commit/4b3d38b05b3ed74fc3c0d77e00fa2ed245e6325c) | ||||||
|  | - Now importing runner overview [`77e9c20`](https://git.odit.services/lfk/frontend/commit/77e9c205f94cf56c2e3584444899adb1e8bdf3c6) | ||||||
|  | - CardsOverview - move to 'enabled' language key [`df53c07`](https://git.odit.services/lfk/frontend/commit/df53c0745035a220d4c07fdce1b5a5e4d763411d) | ||||||
|  | - ✒ typo - "Geb" -> "Gebe" [`f794af0`](https://git.odit.services/lfk/frontend/commit/f794af0950de59a7a7b468c30abdcb5c145f65fb) | ||||||
|  | - Bumped lfk client lib version [`3cd0468`](https://git.odit.services/lfk/frontend/commit/3cd0468b1921824b131178cb02677540b079f9b0) | ||||||
|  | - drop console log - CardDetailModal [`40899e9`](https://git.odit.services/lfk/frontend/commit/40899e9d80ba07a3fbbcac72782db53d98dc318e) | ||||||
|  | - Removed debug info [`55693de`](https://git.odit.services/lfk/frontend/commit/55693de93420c2d76af296fcacc6bcad644a3cbf) | ||||||
|  |  | ||||||
|  | #### [0.8.7](https://git.odit.services/lfk/frontend/compare/0.8.6...0.8.7) | ||||||
|  |  | ||||||
|  | > 25 March 2021 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v0.8.7 [`0af2647`](https://git.odit.services/lfk/frontend/commit/0af26479656393b0baea88f6f83c778740a67e62) | ||||||
|  | - Fixed listen on wrong permission🐞 [`0844215`](https://git.odit.services/lfk/frontend/commit/08442154f4bf94fc1101808b4585dc1f95afe8b2) | ||||||
|  |  | ||||||
|  | #### [0.8.6](https://git.odit.services/lfk/frontend/compare/0.8.5...0.8.6) | ||||||
|  |  | ||||||
|  | > 25 March 2021 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v0.8.6 [`c3c95bf`](https://git.odit.services/lfk/frontend/commit/c3c95bf2916618efe6764a33d9a42d35764d15be) | ||||||
|  | - Merge pull request 'Know Production Bugs 🐞' (#109) from bugfix/107-prod_issues into dev [`d2050b5`](https://git.odit.services/lfk/frontend/commit/d2050b5948890a6077cbb41d82d1a6a1d1106652) | ||||||
|  | - Errors now toast errors❌ [`17e0805`](https://git.odit.services/lfk/frontend/commit/17e0805fe64f6d181f55b81afa502ee6443ebabe) | ||||||
|  | - Sorted translations 👀 [`82b1811`](https://git.odit.services/lfk/frontend/commit/82b1811971b974b686e7618b8a381e1589c168f6) | ||||||
|  | - Fixed missing translations for scanstations🌍 [`aeadef6`](https://git.odit.services/lfk/frontend/commit/aeadef60bbe71da09bb569d20ca7377645beba7f) | ||||||
|  | - Sorted translations🌍 [`a1ab65a`](https://git.odit.services/lfk/frontend/commit/a1ab65a0e975c02c01c603bf6d95a79ada1caa0b) | ||||||
|  | - Fixed runner import getting triggered with invalid information [`ddd9c39`](https://git.odit.services/lfk/frontend/commit/ddd9c396b6bfd39a7b1627d4975151943b367ebf) | ||||||
|  | - Removed middlename search from all files that had it [`6b92405`](https://git.odit.services/lfk/frontend/commit/6b92405bae21e78d694601cbc0b33eed56ef4533) | ||||||
|  | - Fixed mail login bug🐞📧 [`0768939`](https://git.odit.services/lfk/frontend/commit/076893981ff4f7f17330746c561acc570339adac) | ||||||
|  | - Now disabled search by middlename as a quick workaround 🐞 [`49e87cc`](https://git.odit.services/lfk/frontend/commit/49e87ccb15a7ed5edea22a3c3e235f7bee07d3f4) | ||||||
|  | - Fixed conflicting css [`50fffef`](https://git.odit.services/lfk/frontend/commit/50fffef13b8fce885964d8ac277b4ca24d944b2b) | ||||||
|  | - Commented out the buggy runner search to prevent bad UX [`fbe74a5`](https://git.odit.services/lfk/frontend/commit/fbe74a5d8090553a35576a17c97019939cf4f386) | ||||||
|  | - Fixed outsideclick not clearing import modal🛠 [`ef49e50`](https://git.odit.services/lfk/frontend/commit/ef49e507c175510eeb466d33f222755fac8a2a0b) | ||||||
|  |  | ||||||
|  | #### [0.8.5](https://git.odit.services/lfk/frontend/compare/0.8.4...0.8.5) | ||||||
|  |  | ||||||
|  | > 20 March 2021 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v0.8.5 [`e838e6f`](https://git.odit.services/lfk/frontend/commit/e838e6f321bef1565a7e4316890a3c600b242e5a) | ||||||
|  | - Fixed dupliacate mutation 🐞 [`91dd525`](https://git.odit.services/lfk/frontend/commit/91dd5256e9545f62e4342ae5477c36262d6e3401) | ||||||
|  |  | ||||||
|  | #### [0.8.4](https://git.odit.services/lfk/frontend/compare/0.8.3...0.8.4) | ||||||
|  |  | ||||||
|  | > 20 March 2021 | ||||||
|  |  | ||||||
|  | - CONFIG: default_username + default_password [`cc926e8`](https://git.odit.services/lfk/frontend/commit/cc926e84fb8bd9d6c9fd37349e25eb802e1bb324) | ||||||
|  | - 🚀RELEASE v0.8.4 [`3d4dc2d`](https://git.odit.services/lfk/frontend/commit/3d4dc2d72b129f0134ae9f230810c3301dbd5caa) | ||||||
|  | - CONFIG: add 'demo' as default username/password [`ba34710`](https://git.odit.services/lfk/frontend/commit/ba3471068ab00e2d5dbe21d6d763094e662f8347) | ||||||
|  |  | ||||||
|  | #### [0.8.3](https://git.odit.services/lfk/frontend/compare/0.8.2...0.8.3) | ||||||
|  |  | ||||||
|  | > 20 March 2021 | ||||||
|  |  | ||||||
|  | - Sorted translation 🌍 [`d6f6d10`](https://git.odit.services/lfk/frontend/commit/d6f6d10cb6b639a1f988e0da4811355750b0f027) | ||||||
|  | - Smaller bugfixes [`8e04377`](https://git.odit.services/lfk/frontend/commit/8e0437728bd04223a23cdf1879c6c739ca8ebef7) | ||||||
|  | - More small fixes [`1249904`](https://git.odit.services/lfk/frontend/commit/12499045824c13a3ee35c6cc8c3c3a3130dbec12) | ||||||
|  | - 🚀RELEASE v0.8.3 [`fff16e6`](https://git.odit.services/lfk/frontend/commit/fff16e6650cce1231a8d0db43531bf8e3e01f84a) | ||||||
|  |  | ||||||
|  | #### [0.8.2](https://git.odit.services/lfk/frontend/compare/0.8.1...0.8.2) | ||||||
|  |  | ||||||
|  | > 20 March 2021 | ||||||
|  |  | ||||||
|  | - Now using env base url [`aa8196d`](https://git.odit.services/lfk/frontend/commit/aa8196db3a9ff1bcd2b5f0ce655957bfa4e310ab) | ||||||
|  | - 🚀RELEASE v0.8.2 [`fb0c071`](https://git.odit.services/lfk/frontend/commit/fb0c0718e405312f239bc3829b3d9c203d246458) | ||||||
|  |  | ||||||
| #### [0.8.1](https://git.odit.services/lfk/frontend/compare/0.8.0...0.8.1) | #### [0.8.1](https://git.odit.services/lfk/frontend/compare/0.8.0...0.8.1) | ||||||
|  |  | ||||||
|  | > 20 March 2021 | ||||||
|  |  | ||||||
| - ⚡ CI - add build:tags pipeline [`910a086`](https://git.odit.services/lfk/frontend/commit/910a0860a0bd240c5ff9d23dc33923f941b1e10b) | - ⚡ CI - add build:tags pipeline [`910a086`](https://git.odit.services/lfk/frontend/commit/910a0860a0bd240c5ff9d23dc33923f941b1e10b) | ||||||
|  | - 🚀RELEASE v0.8.1 [`b2223b5`](https://git.odit.services/lfk/frontend/commit/b2223b5110cc31740e69de66c74ab3f83a046308) | ||||||
|  |  | ||||||
| #### [0.8.0](https://git.odit.services/lfk/frontend/compare/0.7.0...0.8.0) | #### [0.8.0](https://git.odit.services/lfk/frontend/compare/0.7.0...0.8.0) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +0,0 @@ | |||||||
| const config = { |  | ||||||
| 	baseurl: 'https://dev.lauf-fuer-kaya.de', |  | ||||||
| 	documentserver_key: 'NqZSYTy5AFQ7MppbLW5moqpTk7u7YrNUHKYhKYuThnnya2WpCOIU694hIZT1FzYe', |  | ||||||
| 	fallback_username: 'admin', |  | ||||||
| 	fallback_password: '72fpTzsev4xUu78QPs2FCbwZ3', |  | ||||||
| 	prefersHashRouting: true |  | ||||||
| }; |  | ||||||
| @@ -14,7 +14,7 @@ | |||||||
| </head> | </head> | ||||||
|  |  | ||||||
| <body> | <body> | ||||||
|   <span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.8.1-RELEASE_INFO</span> |   <span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.9.0-RELEASE_INFO</span> | ||||||
|   <noscript>You need to enable JavaScript to run this app.</noscript> |   <noscript>You need to enable JavaScript to run this app.</noscript> | ||||||
|   <script src="/env.js"></script> |   <script src="/env.js"></script> | ||||||
|   <script defer type="module" src="/_dist_/index.js"></script> |   <script defer type="module" src="/_dist_/index.js"></script> | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
| 	"name": "@odit/lfk-frontend", | 	"name": "@odit/lfk-frontend", | ||||||
| 	"version": "0.8.1", | 	"version": "0.9.0", | ||||||
| 	"scripts": { | 	"scripts": { | ||||||
| 		"i18n-order": "node order.js", | 		"i18n-order": "node order.js", | ||||||
| 		"dev:all": "yarn prebuild && snowpack dev", | 		"dev:all": "yarn prebuild && snowpack dev", | ||||||
| @@ -13,7 +13,7 @@ | |||||||
| 	}, | 	}, | ||||||
| 	"license": "CC-BY-NC-SA-4.0", | 	"license": "CC-BY-NC-SA-4.0", | ||||||
| 	"dependencies": { | 	"dependencies": { | ||||||
| 		"@odit/lfk-client-js": "0.6.4", | 		"@odit/lfk-client-js": "0.7.0", | ||||||
| 		"csvtojson": "^2.0.10", | 		"csvtojson": "^2.0.10", | ||||||
| 		"gridjs": "3.3.0", | 		"gridjs": "3.3.0", | ||||||
| 		"localforage": "1.9.0", | 		"localforage": "1.9.0", | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| const config = { | const config = { | ||||||
| 	baseurl: 'http://localhost:4010', | 	baseurl: 'http://localhost:4010', | ||||||
| 	documentserver_key: 'NqZSYTy5AFQ7MppbLW5moqpTk7u7YrNUHKYhKYuThnnya2WpCOIU694hIZT1FzYe' | 	documentserver_key: 'NqZSYTy5AFQ7MppbLW5moqpTk7u7YrNUHKYhKYuThnnya2WpCOIU694hIZT1FzYe', | ||||||
| 	// optional | 	// optional | ||||||
|  | 	default_username: 'demo', | ||||||
|  | 	default_password: 'demo', | ||||||
| 	prefersHashRouting: true | 	prefersHashRouting: true | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1 +0,0 @@ | |||||||
| Nostrud tempor dolor aute ea excepteur aute mollit elit eiusmod exercitation. Magna laborum pariatur adipisicing pariatur cupidatat exercitation duis aliquip pariatur sint exercitation deserunt labore. Consectetur id laboris dolore nostrud do velit ipsum. Eu laboris velit do commodo ad ea sint ex cillum. Cillum ipsum qui eiusmod laborum mollit sunt dolore incididunt. Cillum sunt culpa veniam voluptate et qui ut magna anim occaecat ut mollit dolor. Duis irure proident eu incididunt dolore sunt nisi aute dolore amet eu fugiat laboris quis. |  | ||||||
							
								
								
									
										440
									
								
								src/App.svelte
									
									
									
									
									
								
							
							
						
						
									
										440
									
								
								src/App.svelte
									
									
									
									
									
								
							| @@ -1,216 +1,224 @@ | |||||||
| <script> | <script> | ||||||
|   import "./TailwindStyles.svelte"; |   import "./TailwindStyles.svelte"; | ||||||
|   import "toastify-js/src/toastify.css"; |   import "toastify-js/src/toastify.css"; | ||||||
|   import "gridjs/dist/theme/mermaid.css"; |   import "gridjs/dist/theme/mermaid.css"; | ||||||
|   import { Route, router } from "tinro"; |   import { Route, router } from "tinro"; | ||||||
|   router.subscribe((routeInfo) => { |   router.subscribe((routeInfo) => { | ||||||
|     window.scrollTo(0, 0); |     window.scrollTo(0, 0); | ||||||
|   }); |   }); | ||||||
|   if (config.prefersHashRouting) { |   if (config.prefersHashRouting) { | ||||||
|     if (config.prefersHashRouting === true) { |     if (config.prefersHashRouting === true) { | ||||||
|       router.useHashNavigation(); |       router.useHashNavigation(); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   import localForage from "localforage"; |   import localForage from "localforage"; | ||||||
|   import { addMessages, init, getLocaleFromNavigator } from "svelte-i18n"; |   import { addMessages, init, getLocaleFromNavigator } from "svelte-i18n"; | ||||||
|   import en from "./locales/en.json"; |   import en from "./locales/en.json"; | ||||||
|   import de from "./locales/de.json"; |   import de from "./locales/de.json"; | ||||||
|   addMessages("en", en); |   addMessages("en", en); | ||||||
|   addMessages("de", de); |   addMessages("de", de); | ||||||
|   init({ |   init({ | ||||||
|     fallbackLocale: "en", |     fallbackLocale: "en", | ||||||
|     initialLocale: getLocaleFromNavigator(), |     initialLocale: getLocaleFromNavigator(), | ||||||
|   }); |   }); | ||||||
|   localForage.config({ |   localForage.config({ | ||||||
|     name: "lfk_admin", |     name: "lfk_admin", | ||||||
|     version: 1.0, |     version: 1.0, | ||||||
|     storeName: "lfk_admin", |     storeName: "lfk_admin", | ||||||
|     description: "LfK! admin dashbaord", |     description: "LfK! admin dashbaord", | ||||||
|   }); |   }); | ||||||
|   window.onunhandledrejection = (event) => { |   window.onunhandledrejection = (event) => { | ||||||
|     if (event.reason.toString() == "Error: Unauthorized") { |     if (event.reason.toString() == "Error: Unauthorized") { | ||||||
|       console.log("Found 1"); |       console.log("Found 1"); | ||||||
|       localForage.clear(); |       localForage.clear(); | ||||||
|       location.replace("/"); |       location.replace("/"); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|   // |   // | ||||||
|   import Login from "./components/auth/Login.svelte"; |   import Login from "./components/auth/Login.svelte"; | ||||||
|   import Dashboard from "./components/dashboard/Dashboard.svelte"; |   import Dashboard from "./components/dashboard/Dashboard.svelte"; | ||||||
|   import store from "./store.js"; |   import store from "./store.js"; | ||||||
|   import ForgotPassword from "./components/auth/ForgotPassword.svelte"; |   import ForgotPassword from "./components/auth/ForgotPassword.svelte"; | ||||||
|   import MainDashContent from "./components/dashboard/MainDashContent.svelte"; |   import MainDashContent from "./components/dashboard/MainDashContent.svelte"; | ||||||
|   import Users from "./components/users/Users.svelte"; |   import Users from "./components/users/Users.svelte"; | ||||||
|   import About from "./components/general/About.svelte"; |   import About from "./components/general/About.svelte"; | ||||||
|   import Settings from "./components/settings/Settings.svelte"; |   import Settings from "./components/settings/Settings.svelte"; | ||||||
|   import Transition from "./components/base/Transition.svelte"; |   import Transition from "./components/base/Transition.svelte"; | ||||||
|   import Orgs from "./components/orgs/Orgs.svelte"; |   import Orgs from "./components/orgs/Orgs.svelte"; | ||||||
|   import Runners from "./components/runners/Runners.svelte"; |   import Runners from "./components/runners/Runners.svelte"; | ||||||
|   import Footer from "./components/general/Footer.svelte"; |   import Footer from "./components/general/Footer.svelte"; | ||||||
|   import TracksOverview from "./components/tracks/TracksOverview.svelte"; |   import TracksOverview from "./components/tracks/TracksOverview.svelte"; | ||||||
|   import OrgDetail from "./components/orgs/OrgDetail.svelte"; |   import OrgDetail from "./components/orgs/OrgDetail.svelte"; | ||||||
|   import Teams from "./components/teams/Teams.svelte"; |   import Teams from "./components/teams/Teams.svelte"; | ||||||
|   import { OpenAPI } from "@odit/lfk-client-js"; |   import { OpenAPI } from "@odit/lfk-client-js"; | ||||||
|   import UserDetail from "./components/users/UserDetail.svelte"; |   import UserDetail from "./components/users/UserDetail.svelte"; | ||||||
|   OpenAPI.BASE = config.baseurl; |   OpenAPI.BASE = config.baseurl; | ||||||
|   import { register as registerSW } from "./swmodule"; |   import { register as registerSW } from "./swmodule"; | ||||||
|   import TeamDetail from "./components/teams/TeamDetail.svelte"; |   import TeamDetail from "./components/teams/TeamDetail.svelte"; | ||||||
|   import UserPermissions from "./components/users/UserPermissions.svelte"; |   import UserPermissions from "./components/users/UserPermissions.svelte"; | ||||||
|   import GroupPermissions from "./components/groups/GroupPermissions.svelte"; |   import GroupPermissions from "./components/groups/GroupPermissions.svelte"; | ||||||
|   import RunnerDetail from "./components/runners/RunnerDetail.svelte"; |   import RunnerDetail from "./components/runners/RunnerDetail.svelte"; | ||||||
|   import Imprint from "./components/general/Imprint.svelte"; |   import Imprint from "./components/general/Imprint.svelte"; | ||||||
|   import Privacy from "./components/general/Privacy.svelte"; |   import Privacy from "./components/general/Privacy.svelte"; | ||||||
|   import ResetPassword from "./components/auth/ResetPassword.svelte"; |   import ResetPassword from "./components/auth/ResetPassword.svelte"; | ||||||
|   import Contacts from "./components/contacts/Contacts.svelte"; |   import Contacts from "./components/contacts/Contacts.svelte"; | ||||||
|   import ContactDetail from "./components/contacts/ContactDetail.svelte"; |   import ContactDetail from "./components/contacts/ContactDetail.svelte"; | ||||||
|   import Donors from "./components/donors/Donors.svelte"; |   import Donors from "./components/donors/Donors.svelte"; | ||||||
|   import Groups from "./components/groups/Groups.svelte"; |   import Groups from "./components/groups/Groups.svelte"; | ||||||
|   import DonorDetail from "./components/donors/DonorDetail.svelte"; |   import DonorDetail from "./components/donors/DonorDetail.svelte"; | ||||||
|   import Donations from "./components/donations/Donations.svelte"; |   import Donations from "./components/donations/Donations.svelte"; | ||||||
|   import DonationDetail from "./components/donations/DonationDetail.svelte"; |   import DonationDetail from "./components/donations/DonationDetail.svelte"; | ||||||
|   import GroupDetail from "./components/groups/GroupDetail.svelte"; |   import GroupDetail from "./components/groups/GroupDetail.svelte"; | ||||||
|   import ScanStationsOverview from "./components/scanstations/ScanStationsOverview.svelte"; |   import ScanStations from "./components/scanstations/ScanStations.svelte"; | ||||||
|   import ScanStations from "./components/scanstations/ScanStations.svelte"; |   import ScanStationDetail from "./components/scanstations/ScanStationDetail.svelte"; | ||||||
|   import ScanStationDetail from "./components/scanstations/ScanStationDetail.svelte"; |   import Scans from "./components/scans/Scans.svelte"; | ||||||
|   import Scans from "./components/scans/Scans.svelte"; |   import ScanDetail from "./components/scans/ScanDetail.svelte"; | ||||||
| import ScanDetail from "./components/scans/ScanDetail.svelte"; |   import Cards from "./components/cards/Cards.svelte"; | ||||||
|   store.init(); |   store.init(); | ||||||
|   registerSW(); |   registerSW(); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <Route> | <Route> | ||||||
|   {#if $router.path === '/forgot_password'} |   {#if $router.path === '/forgot_password'} | ||||||
|     <Route path="/forgot_password"> |     <Route path="/forgot_password"> | ||||||
|       <ForgotPassword /> |       <ForgotPassword /> | ||||||
|     </Route> |     </Route> | ||||||
|   {:else if $router.path.includes('/reset')} |   {:else if $router.path.includes('/reset')} | ||||||
|     <Route path="/reset/:resetkey" let:params> |     <Route path="/reset/:resetkey" let:params> | ||||||
|       <ResetPassword {params} /> |       <ResetPassword {params} /> | ||||||
|     </Route> |     </Route> | ||||||
|   {:else if $router.path === '/about'} |   {:else if $router.path === '/about'} | ||||||
|     <Route path="/about"> |     <Route path="/about"> | ||||||
|       <About /> |       <About /> | ||||||
|     </Route> |     </Route> | ||||||
|   {:else if $router.path === '/imprint'} |   {:else if $router.path === '/imprint'} | ||||||
|     <Route path="/imprint"> |     <Route path="/imprint"> | ||||||
|       <Imprint /> |       <Imprint /> | ||||||
|     </Route> |     </Route> | ||||||
|   {:else if $router.path === '/privacy'} |   {:else if $router.path === '/privacy'} | ||||||
|     <Route path="/privacy"> |     <Route path="/privacy"> | ||||||
|       <Privacy /> |       <Privacy /> | ||||||
|     </Route> |     </Route> | ||||||
|   {:else if $store.isLoggedIn} |   {:else if $store.isLoggedIn} | ||||||
|     <Dashboard> |     <Dashboard> | ||||||
|       <Transition> |       <Transition> | ||||||
|         <Route path="/"> |         <Route path="/"> | ||||||
|           <MainDashContent /> |           <MainDashContent /> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/users/*"> |         <Route path="/users/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Users /> |             <Users /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:userid/*" let:params> |           <Route path="/:userid/*" let:params> | ||||||
|             <Route path="/"> |             <Route path="/"> | ||||||
|               <UserDetail {params} /> |               <UserDetail {params} /> | ||||||
|             </Route> |             </Route> | ||||||
|             <Route path="/permissions/"> |             <Route path="/permissions/"> | ||||||
|               <UserPermissions {params} /> |               <UserPermissions {params} /> | ||||||
|             </Route> |             </Route> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/groups/*"> |         <Route path="/groups/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Groups /> |             <Groups /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:groupid/*" let:params> |           <Route path="/:groupid/*" let:params> | ||||||
|             <Route path="/"> |             <Route path="/"> | ||||||
|               <GroupDetail {params} /> |               <GroupDetail {params} /> | ||||||
|             </Route> |             </Route> | ||||||
|             <Route path="/permissions/"> |             <Route path="/permissions/"> | ||||||
|               <GroupPermissions {params} /> |               <GroupPermissions {params} /> | ||||||
|             </Route> |             </Route> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/tracks/*"> |         <Route path="/tracks/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <TracksOverview /> |             <TracksOverview /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:trackid" let:params /> |           <Route path="/:trackid" let:params /> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/runners/*"> |         <Route path="/runners/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Runners /> |             <Runners /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:runnerid" let:params> |           <Route path="/:runnerid" let:params> | ||||||
|             <RunnerDetail {params} /> |             <RunnerDetail {params} /> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/teams/*"> |         <Route path="/teams/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Teams /> |             <Teams /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:teamid" let:params> |           <Route path="/:teamid" let:params> | ||||||
|             <TeamDetail {params} /> |             <TeamDetail {params} /> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/contacts/*"> |         <Route path="/contacts/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Contacts /> |             <Contacts /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:contact" let:params> |           <Route path="/:contact" let:params> | ||||||
|             <ContactDetail {params} /> |             <ContactDetail {params} /> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/orgs/*"> |         <Route path="/orgs/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Orgs /> |             <Orgs /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:orgid" let:params> |           <Route path="/:orgid" let:params> | ||||||
|             <OrgDetail {params} /> |             <OrgDetail {params} /> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/donors/*"> |         <Route path="/donors/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Donors /> |             <Donors /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:donorid" let:params> |           <Route path="/:donorid" let:params> | ||||||
|             <DonorDetail {params} /> |             <DonorDetail {params} /> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/donations/*"> |         <Route path="/donations/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Donations /> |             <Donations /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:donationid" let:params> |           <Route path="/:donationid" let:params> | ||||||
|             <DonationDetail {params} /> |             <DonationDetail {params} /> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/scans/*"> |         <Route path="/cards/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Scans /> |             <Cards /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:scanid" let:params> |           <!-- <Route path="/:scanid" let:params> | ||||||
|             <ScanDetail {params} /> |             <ScanDetail {params} /> | ||||||
|           </Route> |           </Route> --> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/scanstations/*"> |         <Route path="/scans/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <ScanStations /> |             <Scans /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:stationid" let:params> |           <Route path="/:scanid" let:params> | ||||||
|             <ScanStationDetail {params} /> |             <ScanDetail {params} /> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/about"> |         <Route path="/scanstations/*"> | ||||||
|           <About /> |           <Route path="/"> | ||||||
|         </Route> |             <ScanStations /> | ||||||
|         <Route path="/settings"> |           </Route> | ||||||
|           <Settings /> |           <Route path="/:stationid" let:params> | ||||||
|         </Route> |             <ScanStationDetail {params} /> | ||||||
|       </Transition> |           </Route> | ||||||
|       <Footer /> |         </Route> | ||||||
|     </Dashboard> |         <Route path="/about"> | ||||||
|   {:else} |           <About /> | ||||||
|     <Login /> |         </Route> | ||||||
|   {/if} |         <Route path="/settings"> | ||||||
| </Route> |           <Settings /> | ||||||
|  |         </Route> | ||||||
|  |       </Transition> | ||||||
|  |       <Footer /> | ||||||
|  |     </Dashboard> | ||||||
|  |   {:else} | ||||||
|  |     <Login /> | ||||||
|  |   {/if} | ||||||
|  | </Route> | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
|   let usersEmail = ""; |   let usersEmail = ""; | ||||||
|   function reset() { |   function reset() { | ||||||
|     if (isEmail(usersEmail)) { |     if (isEmail(usersEmail)) { | ||||||
|       AuthService.authControllerGetResetToken({ email: usersEmail }) |       AuthService.authControllerGetResetToken("de", { email: usersEmail }) | ||||||
|         .then((resp) => { |         .then((resp) => { | ||||||
|           Toastify({ |           Toastify({ | ||||||
|             text: $_("mail-validation-in-progress"), |             text: $_("mail-validation-in-progress"), | ||||||
|   | |||||||
| @@ -5,10 +5,11 @@ | |||||||
|   store.init(); |   store.init(); | ||||||
|   import { OpenAPI, AuthService } from "@odit/lfk-client-js"; |   import { OpenAPI, AuthService } from "@odit/lfk-client-js"; | ||||||
|   import Footer from "../general/Footer.svelte"; |   import Footer from "../general/Footer.svelte"; | ||||||
|  |   import isEmail from "validator/es/lib/isEmail"; | ||||||
|   import Toastify from "toastify-js"; |   import Toastify from "toastify-js"; | ||||||
|   // ------ |   // ------ | ||||||
|   let username = "demo"; |   let username = config.default_username || ""; | ||||||
|   let password = "demo"; |   let password = config.default_password || ""; | ||||||
|   let is_blocked_by_autologin = false; |   let is_blocked_by_autologin = false; | ||||||
|   let last_loginclick_processed = true; |   let last_loginclick_processed = true; | ||||||
|  |  | ||||||
| @@ -36,10 +37,19 @@ | |||||||
|         text: $_("login_is_checked"), |         text: $_("login_is_checked"), | ||||||
|         duration: 500, |         duration: 500, | ||||||
|       }).showToast(); |       }).showToast(); | ||||||
|       AuthService.authControllerLogin({ |       let postdata = {}; | ||||||
|         username, |       if (isEmail(username)) { | ||||||
|         password, |         postdata = { | ||||||
|       }) |           email: username, | ||||||
|  |           password, | ||||||
|  |         }; | ||||||
|  |       } else { | ||||||
|  |         postdata = { | ||||||
|  |           username, | ||||||
|  |           password, | ||||||
|  |         }; | ||||||
|  |       } | ||||||
|  |       AuthService.authControllerLogin(postdata) | ||||||
|         .then(async (result) => { |         .then(async (result) => { | ||||||
|           await localForage.setItem("logindata", result); |           await localForage.setItem("logindata", result); | ||||||
|           OpenAPI.TOKEN = result.access_token; |           OpenAPI.TOKEN = result.access_token; | ||||||
|   | |||||||
							
								
								
									
										158
									
								
								src/components/cards/AddCardBulkModal.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/components/cards/AddCardBulkModal.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import { clickOutside } from "../base/outsideclick"; | ||||||
|  |   import { focusTrap } from "svelte-focus-trap"; | ||||||
|  |   import { RunnerCardService } from "@odit/lfk-client-js"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   export let bulk_modal_open; | ||||||
|  |   export let current_cards; | ||||||
|  |   function focus(el) { | ||||||
|  |     el.focus(); | ||||||
|  |   } | ||||||
|  |   $: card_count = 0; | ||||||
|  |   $: is_card_count_valid = card_count > 0; | ||||||
|  |   $: processed_last_submit = true; | ||||||
|  |   $: createbtnenabled = is_card_count_valid; | ||||||
|  |   (() => { | ||||||
|  |     document.onkeydown = (e) => { | ||||||
|  |       e = e || window.event; | ||||||
|  |       if (e.key === "Escape") { | ||||||
|  |         bulk_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: $_("creating-blanco-cards"), | ||||||
|  |         duration: -1, | ||||||
|  |       }).showToast(); | ||||||
|  |       RunnerCardService.runnerCardControllerPostBlancoBulk(card_count) | ||||||
|  |         .then((result) => { | ||||||
|  |           bulk_modal_open = false; | ||||||
|  |           // | ||||||
|  |           Toastify({ | ||||||
|  |             text: $_("created-blanco-cards"), | ||||||
|  |             duration: 500, | ||||||
|  |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |           }).showToast(); | ||||||
|  |         }) | ||||||
|  |         .catch((err) => { | ||||||
|  |           // | ||||||
|  |         }) | ||||||
|  |         .finally(() => { | ||||||
|  |           processed_last_submit = true; | ||||||
|  |           // | ||||||
|  |           toast.hideToast(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if bulk_modal_open} | ||||||
|  |   <div | ||||||
|  |     class="fixed z-10 inset-0 overflow-y-auto" | ||||||
|  |     use:focusTrap | ||||||
|  |     use:clickOutside | ||||||
|  |     on:click_outside={() => { | ||||||
|  |       bulk_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">​</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"> | ||||||
|  |                 {$_('create-bulk-blanco-cards')} | ||||||
|  |               </h3> | ||||||
|  |               <div class="mt-2 mb-6"> | ||||||
|  |                 <p class="text-sm text-gray-500"> | ||||||
|  |                   {$_('just-enter-how-many-you-want-and-the-system-will-create-them')} | ||||||
|  |                 </p> | ||||||
|  |               </div> | ||||||
|  |               <div class="grid grid-cols-6 gap-6"> | ||||||
|  |                 <div class="col-span-6"> | ||||||
|  |                   <label | ||||||
|  |                     for="amount" | ||||||
|  |                     class="block text-sm font-medium text-gray-700">{$_('amount')}</label> | ||||||
|  |                   <div class="mt-1 flex rounded-md shadow-sm"> | ||||||
|  |                     <input | ||||||
|  |                       autocomplete="off" | ||||||
|  |                       class:border-red-500={!is_card_count_valid} | ||||||
|  |                       class:focus:border-red-500={!is_card_count_valid} | ||||||
|  |                       class:focus:ring-red-500={!is_card_count_valid} | ||||||
|  |                       bind:value={card_count} | ||||||
|  |                       type="number" | ||||||
|  |                       step="1" | ||||||
|  |                       name="amount" | ||||||
|  |                       class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 p-2" | ||||||
|  |                       placeholder="400" /> | ||||||
|  |                     <span | ||||||
|  |                       class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm">{$_('cards')}</span> | ||||||
|  |                   </div> | ||||||
|  |                   {#if !is_card_count_valid} | ||||||
|  |                     <span | ||||||
|  |                       class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> | ||||||
|  |                       {$_('you-must-create-at-least-one-card-or-cancel')} | ||||||
|  |                     </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"> | ||||||
|  |             {$_('create')} | ||||||
|  |           </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"> | ||||||
|  |             {$_('cancel')} | ||||||
|  |           </button> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | {/if} | ||||||
							
								
								
									
										170
									
								
								src/components/cards/AddCardModal.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								src/components/cards/AddCardModal.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,170 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import { clickOutside } from "../base/outsideclick"; | ||||||
|  |   import { focusTrap } from "svelte-focus-trap"; | ||||||
|  |   import { | ||||||
|  |     RunnerCardService, | ||||||
|  |     RunnerService, | ||||||
|  |     ScanService, | ||||||
|  |   } from "@odit/lfk-client-js"; | ||||||
|  |   import Select from "svelte-select"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   export let modal_open; | ||||||
|  |   export let current_cards; | ||||||
|  |   const getRunnerLabel = (option) => | ||||||
|  |     option.firstname + " " + (option.middlename || "") + " " + option.lastname; | ||||||
|  |   const filterRunners = (label, filterText, option) => | ||||||
|  |     label.toLowerCase().includes(filterText.toLowerCase()) || | ||||||
|  |     option.value.toString().startsWith(filterText.toLowerCase()); | ||||||
|  |   function focus(el) { | ||||||
|  |     el.focus(); | ||||||
|  |   } | ||||||
|  |   $: runner = 0; | ||||||
|  |   $: runners = []; | ||||||
|  |   $: enabled = true; | ||||||
|  |   $: processed_last_submit = true; | ||||||
|  |   RunnerService.runnerControllerGetAll().then((val) => { | ||||||
|  |     runners = val.map((r) => { | ||||||
|  |       return { label: getRunnerLabel(r), value: r }; | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |   $: createbtnenabled = true; | ||||||
|  |   (() => { | ||||||
|  |     document.onkeydown = (e) => { | ||||||
|  |       e = e || window.event; | ||||||
|  |       if (e.key === "Escape") { | ||||||
|  |         modal_open = false; | ||||||
|  |       } | ||||||
|  |       if (e.keyCode === 13) { | ||||||
|  |         if (createbtnenabled === true) { | ||||||
|  |           createbtnenabled = false; | ||||||
|  |           submit(); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  |   })(); | ||||||
|  |   function submit() { | ||||||
|  |     if (processed_last_submit === true) { | ||||||
|  |       processed_last_submit = false; | ||||||
|  |       const toast = Toastify({ | ||||||
|  |         text: $_("adding-card"), | ||||||
|  |         duration: -1, | ||||||
|  |       }).showToast(); | ||||||
|  |       let postdata = { | ||||||
|  |         runner, | ||||||
|  |         enabled, | ||||||
|  |       }; | ||||||
|  |       RunnerCardService.runnerCardControllerPost(postdata) | ||||||
|  |         .then((result) => { | ||||||
|  |           runner = 0; | ||||||
|  |           modal_open = false; | ||||||
|  |           // | ||||||
|  |           Toastify({ | ||||||
|  |             text: $_("card-added"), | ||||||
|  |             duration: 500, | ||||||
|  |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |           }).showToast(); | ||||||
|  |           current_cards.push(result); | ||||||
|  |           current_cards = current_cards; | ||||||
|  |         }) | ||||||
|  |         .catch((err) => { | ||||||
|  |           // | ||||||
|  |         }) | ||||||
|  |         .finally(() => { | ||||||
|  |           processed_last_submit = true; | ||||||
|  |           // | ||||||
|  |           toast.hideToast(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if modal_open} | ||||||
|  |   <div | ||||||
|  |     class="fixed z-10 inset-0 overflow-y-auto" | ||||||
|  |     use:focusTrap | ||||||
|  |     use:clickOutside | ||||||
|  |     on:click_outside={() => { | ||||||
|  |       modal_open = false; | ||||||
|  |     }}> | ||||||
|  |     <div | ||||||
|  |       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> | ||||||
|  |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|  |         <div | ||||||
|  |           class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|  |           data-id="modal_backdrop" /> | ||||||
|  |       </div> | ||||||
|  |       <span | ||||||
|  |         class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|  |         aria-hidden="true">​</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"> | ||||||
|  |                 {$_('create-a-new-card')} | ||||||
|  |               </h3> | ||||||
|  |               <div class="mt-2 mb-6"> | ||||||
|  |                 <p class="text-sm text-gray-500"> | ||||||
|  |                   {$_('you-can-provide-a-runner-but-you-dont-have-to')} | ||||||
|  |                   {$_('if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button')} | ||||||
|  |                 </p> | ||||||
|  |               </div> | ||||||
|  |               <div class="grid grid-cols-6 gap-6"> | ||||||
|  |                 <div class="col-span-6"> | ||||||
|  |                   <label | ||||||
|  |                     for="donor" | ||||||
|  |                     class="block text-sm font-medium text-gray-700">{$_('runner')}</label> | ||||||
|  |                   <Select | ||||||
|  |                     containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | ||||||
|  |                     itemFilter={(label, filterText, option) => filterRunners(label, filterText, option)} | ||||||
|  |                     items={runners} | ||||||
|  |                     showChevron={true} | ||||||
|  |                     placeholder={$_('search-for-runner-by-name-or-id')} | ||||||
|  |                     noOptionsMessage={$_('no-runners-found')} | ||||||
|  |                     on:select={(selectedValue) => (runner = selectedValue.detail.value.id)} | ||||||
|  |                     on:clear={() => (runner = null)} /> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> | ||||||
|  |           <button | ||||||
|  |             disabled={!createbtnenabled} | ||||||
|  |             class:opacity-50={!createbtnenabled} | ||||||
|  |             on:click={submit} | ||||||
|  |             type="button" | ||||||
|  |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |             {$_('create')} | ||||||
|  |           </button> | ||||||
|  |           <button | ||||||
|  |             on:click={() => { | ||||||
|  |               modal_open = false; | ||||||
|  |             }} | ||||||
|  |             type="button" | ||||||
|  |             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |             {$_('cancel')} | ||||||
|  |           </button> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | {/if} | ||||||
							
								
								
									
										186
									
								
								src/components/cards/CardDetailModal.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										186
									
								
								src/components/cards/CardDetailModal.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,186 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import { clickOutside } from "../base/outsideclick"; | ||||||
|  |   import { focusTrap } from "svelte-focus-trap"; | ||||||
|  |   import { RunnerCardService, RunnerService } from "@odit/lfk-client-js"; | ||||||
|  |   import Select from "svelte-select"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   export let edit_modal_open; | ||||||
|  |   export let current_cards; | ||||||
|  |   export let runner = {}; | ||||||
|  |   export let editable = {}; | ||||||
|  |   export let original_data = {}; | ||||||
|  |   const getRunnerLabel = (option) => | ||||||
|  |     option.firstname + " " + (option.middlename || "") + " " + option.lastname; | ||||||
|  |   const filterRunners = (label, filterText, option) => | ||||||
|  |     label.toLowerCase().includes(filterText.toLowerCase()) || | ||||||
|  |     option.value.toString().startsWith(filterText.toLowerCase()); | ||||||
|  |   function focus(el) { | ||||||
|  |     el.focus(); | ||||||
|  |   } | ||||||
|  |   $: runners = []; | ||||||
|  |   $: enabled = true; | ||||||
|  |   $: processed_last_submit = true; | ||||||
|  |   RunnerService.runnerControllerGetAll().then((val) => { | ||||||
|  |     runners = val.map((r) => { | ||||||
|  |       return { label: getRunnerLabel(r), value: r }; | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  |   $: createbtnenabled = !( | ||||||
|  |     JSON.stringify(editable) === JSON.stringify(original_data) | ||||||
|  |   ); | ||||||
|  |   (() => { | ||||||
|  |     document.onkeydown = (e) => { | ||||||
|  |       e = e || window.event; | ||||||
|  |       if (e.key === "Escape") { | ||||||
|  |         edit_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-card"), | ||||||
|  |         duration: -1, | ||||||
|  |       }).showToast(); | ||||||
|  |       RunnerCardService.runnerCardControllerPut(original_data.id, editable) | ||||||
|  |         .then((result) => { | ||||||
|  |           let id = original_data.id; | ||||||
|  |           runner = {}; | ||||||
|  |           editable = {}; | ||||||
|  |           original_data = {}; | ||||||
|  |           edit_modal_open = false; | ||||||
|  |           // | ||||||
|  |           Toastify({ | ||||||
|  |             text: $_("card-updated"), | ||||||
|  |             duration: 500, | ||||||
|  |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|  |           }).showToast(); | ||||||
|  |           current_cards[current_cards.findIndex((c) => c.id === id)] = result; | ||||||
|  |           current_cards = current_cards; | ||||||
|  |         }) | ||||||
|  |         .catch((err) => { | ||||||
|  |           // | ||||||
|  |         }) | ||||||
|  |         .finally(() => { | ||||||
|  |           processed_last_submit = true; | ||||||
|  |           // | ||||||
|  |           toast.hideToast(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if edit_modal_open} | ||||||
|  |   <div | ||||||
|  |     class="fixed z-10 inset-0 overflow-y-auto" | ||||||
|  |     use:focusTrap | ||||||
|  |     use:clickOutside | ||||||
|  |     on:click_outside={() => { | ||||||
|  |       edit_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">​</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"> | ||||||
|  |                 {$_('edit-a-card')} | ||||||
|  |               </h3> | ||||||
|  |               <div class="mt-2 mb-6"> | ||||||
|  |                 <p class="text-sm text-gray-500"> | ||||||
|  |                   {$_('you-can-provide-a-runner-but-you-dont-have-to')} | ||||||
|  |                 </p> | ||||||
|  |               </div> | ||||||
|  |               <div class="grid grid-cols-6 gap-6"> | ||||||
|  |                 <div class="col-span-6"> | ||||||
|  |                   <label | ||||||
|  |                     for="runner" | ||||||
|  |                     class="block text-sm font-medium text-gray-700">{$_('runner')}</label> | ||||||
|  |                   <Select | ||||||
|  |                     containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | ||||||
|  |                     itemFilter={(label, filterText, option) => filterRunners(label, filterText, option)} | ||||||
|  |                     items={runners} | ||||||
|  |                     showChevron={true} | ||||||
|  |                     placeholder={$_('search-for-runner-by-name-or-id')} | ||||||
|  |                     noOptionsMessage={$_('no-runners-found')} | ||||||
|  |                     bind:selectedValue={runner} | ||||||
|  |                     on:select={(selectedValue) => (editable.runner = selectedValue.detail.value.id)} | ||||||
|  |                     on:clear={() => (editable.runner = null)} /> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="col-span-6"> | ||||||
|  |                   <p class="text-gray-500"> | ||||||
|  |                     <input | ||||||
|  |                       id="enabled" | ||||||
|  |                       on:change={() => { | ||||||
|  |                         editable.enabled = !editable.enabled; | ||||||
|  |                       }} | ||||||
|  |                       name="enabled" | ||||||
|  |                       type="checkbox" | ||||||
|  |                       checked={editable.enabled} | ||||||
|  |                       class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" /> | ||||||
|  |                     {$_('this-card-is')} | ||||||
|  |                     {#if editable.enabled} | ||||||
|  |                       {$_('enabled')} | ||||||
|  |                     {:else}{$_('disabled')}{/if} | ||||||
|  |                   </p> | ||||||
|  |                 </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={() => { | ||||||
|  |               edit_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} | ||||||
							
								
								
									
										40
									
								
								src/components/cards/Cards.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/components/cards/Cards.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import store from "../../store"; | ||||||
|  |   import AddCardBulkModal from "./AddCardBulkModal.svelte"; | ||||||
|  |   import AddCardModal from "./AddCardModal.svelte"; | ||||||
|  |   import CardsOverview from "./CardsOverview.svelte"; | ||||||
|  |   $: current_cards = []; | ||||||
|  |   export let modal_open = false; | ||||||
|  |   export let bulk_modal_open = false; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <section class="container p-5"> | ||||||
|  |   <span class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|  |     {$_('cards')} | ||||||
|  |     {#if store.state.jwtinfo.userdetails.permissions.includes('CARD:CREATE')} | ||||||
|  |       <button | ||||||
|  |         on:click={() => { | ||||||
|  |           modal_open = true; | ||||||
|  |         }} | ||||||
|  |         type="button" | ||||||
|  |         class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |         {$_('add-card')} | ||||||
|  |       </button> | ||||||
|  |       <button | ||||||
|  |         on:click={() => { | ||||||
|  |           bulk_modal_open = true; | ||||||
|  |         }} | ||||||
|  |         type="button" | ||||||
|  |         class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|  |         {$_('create-bulk-cards')} | ||||||
|  |       </button> | ||||||
|  |     {/if} | ||||||
|  |   </span> | ||||||
|  |   <CardsOverview bind:current_cards /> | ||||||
|  | </section> | ||||||
|  |  | ||||||
|  | {#if store.state.jwtinfo.userdetails.permissions.includes('CARD:CREATE')} | ||||||
|  |   <AddCardModal bind:current_cards bind:modal_open /> | ||||||
|  |   <AddCardBulkModal bind:current_cards bind:bulk_modal_open /> | ||||||
|  | {/if} | ||||||
							
								
								
									
										12
									
								
								src/components/cards/CardsEmptyState.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/components/cards/CardsEmptyState.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | <script> | ||||||
|  |   import { _ } from "svelte-i18n"; | ||||||
|  |   import cards_empty from "./cards.svg"; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <div class="text-center items-center justify-center"> | ||||||
|  |   <p class="mb-16 text-lg text-gray-500"> | ||||||
|  |     <img class="m-auto" style="height:15rem" src={cards_empty} alt="" /> | ||||||
|  |     <span class="font-bold">{$_('there-are-no-cards-yet')}</span><br /> | ||||||
|  |     <span>{$_('add-your-first-card')}</span> | ||||||
|  |   </p> | ||||||
|  | </div> | ||||||
							
								
								
									
										237
									
								
								src/components/cards/CardsOverview.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								src/components/cards/CardsOverview.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | |||||||
|  | <script> | ||||||
|  |   import { getLocaleFromNavigator, json, _ } from "svelte-i18n"; | ||||||
|  |   import { RunnerCardService } from "@odit/lfk-client-js"; | ||||||
|  |   import store from "../../store"; | ||||||
|  |   import Toastify from "toastify-js"; | ||||||
|  |   import CardsEmptyState from "./CardsEmptyState.svelte"; | ||||||
|  |   import CardDetailModal from "./CardDetailModal.svelte"; | ||||||
|  |   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|  |   export let edit_modal_open = false; | ||||||
|  |   export let runner = {}; | ||||||
|  |   export let editable = {}; | ||||||
|  |   export let original_data = {}; | ||||||
|  |   export let current_cards = []; | ||||||
|  |   $: searchvalue = ""; | ||||||
|  |   $: active_deletes = []; | ||||||
|  |   $: 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) => { | ||||||
|  |       current_cards = val; | ||||||
|  |     } | ||||||
|  |   ); | ||||||
|  |   function should_display_based_on_id(id) { | ||||||
|  |     if (searchvalue.toString().slice(-1) === "*") { | ||||||
|  |       return id.toString().startsWith(searchvalue.replace("*", "")); | ||||||
|  |     } | ||||||
|  |     return id.toString() === searchvalue; | ||||||
|  |   } | ||||||
|  |   const getRunnerLabel = (option) => | ||||||
|  |     option?.firstname + " " + (option?.middlename || "") + " " + (option?.lastname || "{$_('non-blanko')}"); | ||||||
|  |   function open_edit_modal(card) { | ||||||
|  |     if(card.runner?.id){ | ||||||
|  |       runner = Object.assign( | ||||||
|  |         { runner }, | ||||||
|  |         { label: getRunnerLabel(card.runner), value: card.runner } | ||||||
|  |       ); | ||||||
|  |       card.runner = card.runner.id; | ||||||
|  |     } | ||||||
|  |     else{ | ||||||
|  |       card.runner=null; | ||||||
|  |       runner = null | ||||||
|  |     } | ||||||
|  |     editable = Object.assign(editable, card); | ||||||
|  |     original_data = Object.assign(original_data, card); | ||||||
|  |     edit_modal_open = true; | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if store.state.jwtinfo.userdetails.permissions.includes('CARD:UPDATE')} | ||||||
|  |   <CardDetailModal | ||||||
|  |     bind:current_cards | ||||||
|  |     bind:edit_modal_open | ||||||
|  |     bind:runner | ||||||
|  |     bind:editable | ||||||
|  |     bind:original_data /> | ||||||
|  | {/if} | ||||||
|  |  | ||||||
|  | {#if store.state.jwtinfo.userdetails.permissions.includes('CARD:GET')} | ||||||
|  |   {#await cards_promise} | ||||||
|  |     <div | ||||||
|  |       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|  |       role="alert"> | ||||||
|  |       <p class="font-bold">{$_('loading-cards')}</p> | ||||||
|  |       <p class="text-sm">{$_('this-might-take-a-moment')}</p> | ||||||
|  |     </div> | ||||||
|  |   {:then} | ||||||
|  |     {#if current_cards.length === 0} | ||||||
|  |       <CardsEmptyState /> | ||||||
|  |     {:else} | ||||||
|  |       <input | ||||||
|  |         type="search" | ||||||
|  |         bind:value={searchvalue} | ||||||
|  |         placeholder={$_('datatable.search')} | ||||||
|  |         aria-label={$_('datatable.search')} | ||||||
|  |         class="gridjs-input gridjs-search-input mb-4" /> | ||||||
|  |         <div class="h-12"> | ||||||
|  |           <GenerateRunnerCards | ||||||
|  |             bind:cards_show | ||||||
|  |             bind:generate_cards /> | ||||||
|  |         </div> | ||||||
|  |       <div | ||||||
|  |         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> | ||||||
|  |         <table class="divide-y divide-gray-200 w-full"> | ||||||
|  |           <thead class="bg-gray-50"> | ||||||
|  |             <tr> | ||||||
|  |               <th | ||||||
|  |                 scope="col" | ||||||
|  |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|  |                 <span | ||||||
|  |                   on:click={() => { | ||||||
|  |                     const newstate = !current_cards.some((r) => r.is_selected === true); | ||||||
|  |                     current_cards = current_cards.map((r) => { | ||||||
|  |                       r.is_selected = newstate; | ||||||
|  |                       return r; | ||||||
|  |                     }); | ||||||
|  |                   }} | ||||||
|  |                   class="underline cursor-pointer select-none">{#if current_cards.some((r) => r.is_selected === true)} | ||||||
|  |                     {$_('deselect-all')} | ||||||
|  |                   {:else}{$_('select-all')}{/if} | ||||||
|  |                 </span> | ||||||
|  |               </th> | ||||||
|  |               <th | ||||||
|  |                 scope="col" | ||||||
|  |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|  |                 {$_('code')} | ||||||
|  |               </th> | ||||||
|  |               <th | ||||||
|  |                 scope="col" | ||||||
|  |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|  |                 {$_('runner')} | ||||||
|  |               </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> | ||||||
|  |             </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> | ||||||
|  |  | ||||||
|  |                   {#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> | ||||||
|  |     {/if} | ||||||
|  |   {:catch error} | ||||||
|  |     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> | ||||||
|  |       <span class="inline-block align-middle mr-8"> | ||||||
|  |         <b class="capitalize">{$_('general_promise_error')}</b> | ||||||
|  |         {error} | ||||||
|  |       </span> | ||||||
|  |     </div> | ||||||
|  |   {/await} | ||||||
|  | {/if} | ||||||
							
								
								
									
										1
									
								
								src/components/cards/cards.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/components/cards/cards.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 653.9 247.6"><path d="M272 211l-53 12s-11-2-1-17l4-4 27-14v-2l-6-41-2-16 17-17 4-3 44 41v1l-19 33z" fill="#ffb7b7"/><path d="M253 198l-54 13a6 6 0 01-5-7 16 16 0 012-5 48 48 0 016-9l28-14-4-24-1-12-2-8-2-16 21-19 22 21 22 20-3 5-3 7-17 30-3 6z" fill="#ffb7b7"/><path d="M346 190s-20-1-28-15a24 24 0 01-3-14l-8-17-11-23-30-4-2 1-21 19-7 6-10 9-49 44a37 37 0 01-7 9 50 50 0 01-9 7c-10 5-24 9-44 7L10 248 0 176l89-29 131-86 89 23 41 58z" fill="#ffb7b7"/><path d="M648 0H275a5 5 0 00-5 5v221a5 5 0 005 6h373a5 5 0 006-6V5a5 5 0 00-6-5z" fill="#fff"/><path d="M648 0H275a5 5 0 00-5 5v221a5 5 0 005 6h373a5 5 0 006-6V5a5 5 0 00-6-5zm4 226a4 4 0 01-4 4H275a4 4 0 01-3-4V5a4 4 0 013-3h373a4 4 0 014 3z" fill="#3f3d56"/><path d="M312 30a9 9 0 119-9 9 9 0 01-9 9zm0-17a8 8 0 107 8 8 8 0 00-7-8z" fill="#6c63ff"/><path d="M297 21a8 8 0 016-8 8 8 0 100 16 8 8 0 01-6-8zM349 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM368 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM386 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM415 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM434 130a7 7 0 01-7-7v-20a7 7 0 0113 0v20a7 7 0 01-6 7zM452 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM481 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM499 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM518 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM546 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM565 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7zM583 130a7 7 0 01-7-7v-20a7 7 0 0114 0v20a7 7 0 01-7 7z" fill="#6c63ff"/><path d="M396 208h-99a5 5 0 110-10h99a5 5 0 010 10zM364 188h-35a5 5 0 110-10h35a5 5 0 110 10z" fill="#e6e6e6"/><path fill="#3f3d56" d="M271 46h381v2H271z"/><path opacity=".1" d="M228 203l-1-2 33-15 8-27-12-10 1-1 13 10-8 30-34 15zM196 199l-9 4-17 2a50 50 0 01-9 7l-16-1-26-1 88-74 18 4-29 59z"/><path d="M318 175l-8 1-47 4-29 1-38 18-9 4-70 8 95-81 11 2 20 5 22 5 18 1 24 1 20 1a13 13 0 0112 13c0 7-5 14-21 17z" fill="#ffb7b7"/><path d="M325 170s-7-2-9-9c-2-4-1-9 3-15l1 1c-3 6-4 10-3 14 2 5 9 7 9 7zM197 197l34-16v2l-33 16zM218 135l48-19v2l-41 16 35 6v2l-42-7z" opacity=".1"/></svg> | ||||||
| After Width: | Height: | Size: 2.1 KiB | 
| @@ -1,308 +1,327 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|   import localForage from "localforage"; |   import localForage from "localforage"; | ||||||
|   import store from "../../store"; |   import store from "../../store"; | ||||||
|   import { router } from "tinro"; |   import { router } from "tinro"; | ||||||
|   import NoComponentLoaded from "../base/NoComponentLoaded.svelte"; |   import NoComponentLoaded from "../base/NoComponentLoaded.svelte"; | ||||||
|   import { AuthService } from "@odit/lfk-client-js"; |   import { AuthService } from "@odit/lfk-client-js"; | ||||||
|   $: navOpen = false; |   $: navOpen = false; | ||||||
|   function logout() { |   function logout() { | ||||||
|     localForage.clear(); |     localForage.clear(); | ||||||
|     location.replace("/"); |     location.replace("/"); | ||||||
|   } |   } | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="min-h-screen bg-gray-50"> | <section class="min-h-screen bg-gray-50"> | ||||||
|   <nav |   <nav | ||||||
|     class:-translate-x-full={!navOpen} |     class:-translate-x-full={!navOpen} | ||||||
|     class:translate-x-0={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"> |     class="select-none fixed top-0 left-0 z-20 h-full pb-10 overflow-x-hidden overflow-y-auto transition origin-left transform border-r w-60 md:translate-x-0 bg-gray-50"> | ||||||
|     <a href="/" class="flex items-center px-4 py-5"> |     <a href="/" class="flex items-center px-4 py-5"> | ||||||
|       <img src="/lfk-logo.png" alt="Logo" class="h-10" /> |       <img src="/lfk-logo.png" alt="Logo" class="h-10" /> | ||||||
|       <h3 class="text-lg">Lauf für Kaya! Admin</h3> |       <h3 class="text-lg">Lauf für Kaya! Admin</h3> | ||||||
|     </a> |     </a> | ||||||
|     <nav class="text-sm font-medium text-gray-600" aria-label="Main Navigation"> |     <nav class="text-sm font-medium text-gray-600" aria-label="Main Navigation"> | ||||||
|       <a |       <a | ||||||
|         class:bg-gray-100={$router.path === '/'} |         class:bg-gray-100={$router.path === '/'} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="/"> |         href="/"> | ||||||
|         <svg |         <svg | ||||||
|           class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |           class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|           xmlns="http://www.w3.org/2000/svg" |           xmlns="http://www.w3.org/2000/svg" | ||||||
|           viewBox="0 0 20 20" |           viewBox="0 0 20 20" | ||||||
|           fill="currentColor"> |           fill="currentColor"> | ||||||
|           <path |           <path | ||||||
|             d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z" /> |             d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z" /> | ||||||
|         </svg> |         </svg> | ||||||
|         <span>{$_('dashboard-title')}</span> |         <span>{$_('dashboard-title')}</span> | ||||||
|       </a> |       </a> | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANIZATION:GET')} |       {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANIZATION:GET')} | ||||||
|         <a |         <a | ||||||
|           class:bg-gray-100={$router.path.includes('/orgs/')} |           class:bg-gray-100={$router.path.includes('/orgs/')} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           href="/orgs/"> |           href="/orgs/"> | ||||||
|           <svg |           <svg | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" |             fill="currentColor" | ||||||
|             xmlns="http://www.w3.org/2000/svg" |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             viewBox="0 0 24 24" |             viewBox="0 0 24 24" | ||||||
|             width="24" |             width="24" | ||||||
|             height="24"><path fill="none" d="M0 0h24v24H0z" /> |             height="24"><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|             <path |             <path | ||||||
|               d="M17 19h2v-8h-6v8h2v-6h2v6zM3 19V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v5h2v10h1v2H2v-2h1zm4-8v2h2v-2H7zm0 4v2h2v-2H7zm0-8v2h2V7H7z" /></svg> |               d="M17 19h2v-8h-6v8h2v-6h2v6zM3 19V4a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v5h2v10h1v2H2v-2h1zm4-8v2h2v-2H7zm0 4v2h2v-2H7zm0-8v2h2V7H7z" /></svg> | ||||||
|           <span>{$_('orgs')}</span> |           <span>{$_('orgs')}</span> | ||||||
|         </a> |         </a> | ||||||
|       {/if} |       {/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('USER:GET')} |       {#if store.state.jwtinfo.userdetails.permissions.includes('USER:GET')} | ||||||
|         <a |         <a | ||||||
|           class:bg-gray-100={$router.path === '/users/'} |           class:bg-gray-100={$router.path === '/users/'} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           href="/users/"> |           href="/users/"> | ||||||
|           <svg |           <svg | ||||||
|             xmlns="http://www.w3.org/2000/svg" |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             width="24" |             width="24" | ||||||
|             height="24" |             height="24" | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" |             fill="currentColor" | ||||||
|             viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z" /> |             viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|             <path |             <path | ||||||
|               d="M12 14v8H4a8 8 0 018-8zm0-1a6 6 0 110-12 6 6 0 010 12zm2.6 5.81a3.51 3.51 0 010-1.62l-1-.57 1-1.74 1 .58a3.5 3.5 0 011.4-.82V13.5h2v1.15a3.5 3.5 0 011.4.8l1-.57 1 1.74-1 .57a3.51 3.51 0 010 1.62l1 .57-1 1.74-1-.58a3.5 3.5 0 01-1.4.82v1.14h-2v-1.15a3.5 3.5 0 01-1.4-.8l-1 .57-1-1.74 1-.57zM18 17a1 1 0 100 2 1 1 0 000-2z" /></svg> |               d="M12 14v8H4a8 8 0 018-8zm0-1a6 6 0 110-12 6 6 0 010 12zm2.6 5.81a3.51 3.51 0 010-1.62l-1-.57 1-1.74 1 .58a3.5 3.5 0 011.4-.82V13.5h2v1.15a3.5 3.5 0 011.4.8l1-.57 1 1.74-1 .57a3.51 3.51 0 010 1.62l1 .57-1 1.74-1-.58a3.5 3.5 0 01-1.4.82v1.14h-2v-1.15a3.5 3.5 0 01-1.4-.8l-1 .57-1-1.74 1-.57zM18 17a1 1 0 100 2 1 1 0 000-2z" /></svg> | ||||||
|           <span>{$_('users')}</span> |           <span>{$_('users')}</span> | ||||||
|         </a> |         </a> | ||||||
|       {/if} |       {/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('USERGROUP:GET')} |       {#if store.state.jwtinfo.userdetails.permissions.includes('USERGROUP:GET')} | ||||||
|         <a |         <a | ||||||
|           class:bg-gray-100={$router.path === '/groups/'} |           class:bg-gray-100={$router.path === '/groups/'} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           href="/groups/"> |           href="/groups/"> | ||||||
|           <svg |           <svg | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" |             fill="currentColor" | ||||||
|             width="24" |             width="24" | ||||||
|             height="24" |             height="24" | ||||||
|             xmlns="http://www.w3.org/2000/svg" |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             viewBox="0 0 640 512"><path |             viewBox="0 0 640 512"><path | ||||||
|               fill="currentColor" |               fill="currentColor" | ||||||
|               d="M610.5 341.3c2.6-14.1 2.6-28.5 0-42.6l25.8-14.9c3-1.7 4.3-5.2 3.3-8.5-6.7-21.6-18.2-41.2-33.2-57.4-2.3-2.5-6-3.1-9-1.4l-25.8 14.9c-10.9-9.3-23.4-16.5-36.9-21.3v-29.8c0-3.4-2.4-6.4-5.7-7.1-22.3-5-45-4.8-66.2 0-3.3.7-5.7 3.7-5.7 7.1v29.8c-13.5 4.8-26 12-36.9 21.3l-25.8-14.9c-2.9-1.7-6.7-1.1-9 1.4-15 16.2-26.5 35.8-33.2 57.4-1 3.3.4 6.8 3.3 8.5l25.8 14.9c-2.6 14.1-2.6 28.5 0 42.6l-25.8 14.9c-3 1.7-4.3 5.2-3.3 8.5 6.7 21.6 18.2 41.1 33.2 57.4 2.3 2.5 6 3.1 9 1.4l25.8-14.9c10.9 9.3 23.4 16.5 36.9 21.3v29.8c0 3.4 2.4 6.4 5.7 7.1 22.3 5 45 4.8 66.2 0 3.3-.7 5.7-3.7 5.7-7.1v-29.8c13.5-4.8 26-12 36.9-21.3l25.8 14.9c2.9 1.7 6.7 1.1 9-1.4 15-16.2 26.5-35.8 33.2-57.4 1-3.3-.4-6.8-3.3-8.5l-25.8-14.9zM496 368.5c-26.8 0-48.5-21.8-48.5-48.5s21.8-48.5 48.5-48.5 48.5 21.8 48.5 48.5-21.7 48.5-48.5 48.5zM96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm224 32c1.9 0 3.7-.5 5.6-.6 8.3-21.7 20.5-42.1 36.3-59.2 7.4-8 17.9-12.6 28.9-12.6 6.9 0 13.7 1.8 19.6 5.3l7.9 4.6c.8-.5 1.6-.9 2.4-1.4 7-14.6 11.2-30.8 11.2-48 0-61.9-50.1-112-112-112S208 82.1 208 144c0 61.9 50.1 112 112 112zm105.2 194.5c-2.3-1.2-4.6-2.6-6.8-3.9-8.2 4.8-15.3 9.8-27.5 9.8-10.9 0-21.4-4.6-28.9-12.6-18.3-19.8-32.3-43.9-40.2-69.6-10.7-34.5 24.9-49.7 25.8-50.3-.1-2.6-.1-5.2 0-7.8l-7.9-4.6c-3.8-2.2-7-5-9.8-8.1-3.3.2-6.5.6-9.8.6-24.6 0-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h255.4c-3.7-6-6.2-12.8-6.2-20.3v-9.2zM173.1 274.6C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg> |               d="M610.5 341.3c2.6-14.1 2.6-28.5 0-42.6l25.8-14.9c3-1.7 4.3-5.2 3.3-8.5-6.7-21.6-18.2-41.2-33.2-57.4-2.3-2.5-6-3.1-9-1.4l-25.8 14.9c-10.9-9.3-23.4-16.5-36.9-21.3v-29.8c0-3.4-2.4-6.4-5.7-7.1-22.3-5-45-4.8-66.2 0-3.3.7-5.7 3.7-5.7 7.1v29.8c-13.5 4.8-26 12-36.9 21.3l-25.8-14.9c-2.9-1.7-6.7-1.1-9 1.4-15 16.2-26.5 35.8-33.2 57.4-1 3.3.4 6.8 3.3 8.5l25.8 14.9c-2.6 14.1-2.6 28.5 0 42.6l-25.8 14.9c-3 1.7-4.3 5.2-3.3 8.5 6.7 21.6 18.2 41.1 33.2 57.4 2.3 2.5 6 3.1 9 1.4l25.8-14.9c10.9 9.3 23.4 16.5 36.9 21.3v29.8c0 3.4 2.4 6.4 5.7 7.1 22.3 5 45 4.8 66.2 0 3.3-.7 5.7-3.7 5.7-7.1v-29.8c13.5-4.8 26-12 36.9-21.3l25.8 14.9c2.9 1.7 6.7 1.1 9-1.4 15-16.2 26.5-35.8 33.2-57.4 1-3.3-.4-6.8-3.3-8.5l-25.8-14.9zM496 368.5c-26.8 0-48.5-21.8-48.5-48.5s21.8-48.5 48.5-48.5 48.5 21.8 48.5 48.5-21.7 48.5-48.5 48.5zM96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm224 32c1.9 0 3.7-.5 5.6-.6 8.3-21.7 20.5-42.1 36.3-59.2 7.4-8 17.9-12.6 28.9-12.6 6.9 0 13.7 1.8 19.6 5.3l7.9 4.6c.8-.5 1.6-.9 2.4-1.4 7-14.6 11.2-30.8 11.2-48 0-61.9-50.1-112-112-112S208 82.1 208 144c0 61.9 50.1 112 112 112zm105.2 194.5c-2.3-1.2-4.6-2.6-6.8-3.9-8.2 4.8-15.3 9.8-27.5 9.8-10.9 0-21.4-4.6-28.9-12.6-18.3-19.8-32.3-43.9-40.2-69.6-10.7-34.5 24.9-49.7 25.8-50.3-.1-2.6-.1-5.2 0-7.8l-7.9-4.6c-3.8-2.2-7-5-9.8-8.1-3.3.2-6.5.6-9.8.6-24.6 0-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h255.4c-3.7-6-6.2-12.8-6.2-20.3v-9.2zM173.1 274.6C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg> | ||||||
|           <span>{$_('user-groups')}</span> |           <span>{$_('user-groups')}</span> | ||||||
|         </a> |         </a> | ||||||
|       {/if} |       {/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:GET')} |       {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:GET')} | ||||||
|         <a |         <a | ||||||
|           class:bg-gray-100={$router.path === '/runners/'} |           class:bg-gray-100={$router.path === '/runners/'} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           href="/runners/"> |           href="/runners/"> | ||||||
|           <svg |           <svg | ||||||
|             xmlns="http://www.w3.org/2000/svg" |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             viewBox="0 0 24 24" |             viewBox="0 0 24 24" | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" |             fill="currentColor" | ||||||
|             width="24" |             width="24" | ||||||
|             height="24"><path fill="none" d="M0 0h24v24H0z" /> |             height="24"><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|             <path |             <path | ||||||
|               d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z" /></svg> |               d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z" /></svg> | ||||||
|           <span>{$_('runners')}</span> |           <span>{$_('runners')}</span> | ||||||
|         </a> |         </a> | ||||||
|       {/if} |       {/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:GET')} |       {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:GET')} | ||||||
|         <a |         <a | ||||||
|           class:bg-gray-100={$router.path === '/teams/'} |           class:bg-gray-100={$router.path === '/teams/'} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           href="/teams/"> |           href="/teams/"> | ||||||
|           <svg |           <svg | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" |             fill="currentColor" | ||||||
|             width="24" |             width="24" | ||||||
|             height="24" |             height="24" | ||||||
|             xmlns="http://www.w3.org/2000/svg" |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             viewBox="0 0 640 512"><path |             viewBox="0 0 640 512"><path | ||||||
|               fill="currentColor" |               fill="currentColor" | ||||||
|               d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg> |               d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg> | ||||||
|           <span>{$_('teams')}</span> |           <span>{$_('teams')}</span> | ||||||
|         </a> |         </a> | ||||||
|       {/if} |       {/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:GET')} |       {#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:GET')} | ||||||
|         <a |         <a | ||||||
|           class:bg-gray-100={$router.path.includes('/donors/')} |           class:bg-gray-100={$router.path.includes('/donors/')} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           href="/donors/"> |           href="/donors/"> | ||||||
|           <svg |           <svg | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" |             fill="currentColor" | ||||||
|             xmlns="http://www.w3.org/2000/svg" |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             viewBox="0 0 24 24" |             viewBox="0 0 24 24" | ||||||
|             width="24" |             width="24" | ||||||
|             height="24"><path fill="none" d="M0 0h24v24H0z" /> |             height="24"><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|             <path |             <path | ||||||
|               d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z" /></svg> |               d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z" /></svg> | ||||||
|           <span>{$_('donors')}</span> |           <span>{$_('donors')}</span> | ||||||
|         </a> |         </a> | ||||||
|       {/if} |       {/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:GET')} |       {#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:GET')} | ||||||
|         <a |         <a | ||||||
|           class:bg-gray-100={$router.path.includes('/donations/')} |           class:bg-gray-100={$router.path.includes('/donations/')} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           href="/donations/"> |           href="/donations/"> | ||||||
|           <svg |           <svg | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" |             fill="currentColor" | ||||||
|             xmlns="http://www.w3.org/2000/svg" |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             viewBox="0 0 24 24" |             viewBox="0 0 24 24" | ||||||
|             width="24" |             width="24" | ||||||
|             height="24"><path fill="none" d="M0 0h24v24H0z" /> |             height="24"><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|             <path |             <path | ||||||
|               d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z" /></svg> |               d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z" /></svg> | ||||||
|           <span>{$_('donations')}</span> |           <span>{$_('donations')}</span> | ||||||
|         </a> |         </a> | ||||||
|       {/if} |       {/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('TRACK:GET')} |       {#if store.state.jwtinfo.userdetails.permissions.includes('TRACK:GET')} | ||||||
|         <a |         <a | ||||||
|           class:bg-gray-100={$router.path === '/tracks/'} |           class:bg-gray-100={$router.path === '/tracks/'} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           href="/tracks/"> |           href="/tracks/"> | ||||||
|           <svg |           <svg | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" |             fill="currentColor" | ||||||
|             width="24" |             width="24" | ||||||
|             height="24" |             height="24" | ||||||
|             xmlns="http://www.w3.org/2000/svg" |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             viewBox="0 0 640 512"><path |             viewBox="0 0 640 512"><path | ||||||
|               fill="currentColor" |               fill="currentColor" | ||||||
|               d="M635.7 167.2L556.1 31.7c-8.8-15-28.3-20.1-43.5-11.5l-69 39.1L503.3 161c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L416 75l-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L333.2 122 278 153.3 337.8 255c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-59.7-101.7-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-27.9-47.5-55.2 31.3 59.7 101.7c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L84.9 262.9l-69 39.1C.7 310.7-4.6 329.8 4.2 344.8l79.6 135.6c8.8 15 28.3 20.1 43.5 11.5L624.1 210c15.2-8.6 20.4-27.8 11.6-42.8z" /></svg> |               d="M635.7 167.2L556.1 31.7c-8.8-15-28.3-20.1-43.5-11.5l-69 39.1L503.3 161c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L416 75l-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L333.2 122 278 153.3 337.8 255c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-59.7-101.7-55.2 31.3 27.9 47.4c2.2 3.8.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9l-27.9-47.5-55.2 31.3 59.7 101.7c2.2 3.7.9 8.5-2.9 10.7l-13.8 7.8c-3.8 2.2-8.7.9-10.9-2.9L84.9 262.9l-69 39.1C.7 310.7-4.6 329.8 4.2 344.8l79.6 135.6c8.8 15 28.3 20.1 43.5 11.5L624.1 210c15.2-8.6 20.4-27.8 11.6-42.8z" /></svg> | ||||||
|           <span>{$_('tracks')}</span> |           <span>{$_('tracks')}</span> | ||||||
|         </a> |         </a> | ||||||
|       {/if} |       {/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('SCAN:GET')} |       {#if store.state.jwtinfo.userdetails.permissions.includes('CARD:GET')} | ||||||
|         <a |         <a | ||||||
|           class:bg-gray-100={$router.path === '/scans/'} |           class:bg-gray-100={$router.path === '/cards/'} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           href="/scans/"> |           href="/cards/"> | ||||||
|           <svg |           <svg | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" |             fill="currentColor" | ||||||
|             width="24" |             width="24" | ||||||
|             height="24" |             height="24" | ||||||
|             xmlns="http://www.w3.org/2000/svg" |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z" /> |             viewBox="0 0 24 24"> | ||||||
|             <path |             <path fill="none" d="M0 0h24v24H0z" /> | ||||||
|               fill="currentColor" |             <path | ||||||
|               d="M2 4h2v16H2V4zm4 0h1v16H6V4zm2 0h2v16H8V4zm3 0h2v16h-2V4zm3 0h2v16h-2V4zm3 0h1v16h-1V4zm2 0h3v16h-3V4z" /></svg> |               fill="currentColor" | ||||||
|           <span>Scans</span> |               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> | ||||||
|         </a> |           <span>{$_('cards')}</span> | ||||||
|       {/if} |         </a> | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('CONTACT:GET')} |       {/if} | ||||||
|         <a |       {#if store.state.jwtinfo.userdetails.permissions.includes('SCAN:GET')} | ||||||
|           class:bg-gray-100={$router.path === '/contacts/'} |         <a | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class:bg-gray-100={$router.path === '/scans/'} | ||||||
|           href="/contacts/"> |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           <svg |           href="/scans/"> | ||||||
|             fill="currentColor" |           <svg | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             xmlns="http://www.w3.org/2000/svg" |             fill="currentColor" | ||||||
|             viewBox="0 0 24 24" |             width="24" | ||||||
|             width="24" |             height="24" | ||||||
|             height="24"><path fill="none" d="M0 0h24v24H0z" /> |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             <path |             viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|               d="M2 22a8 8 0 1 1 16 0H2zm8-9c-3.315 0-6-2.685-6-6s2.685-6 6-6 6 2.685 6 6-2.685 6-6 6zm10 4h4v2h-4v-2zm-3-5h7v2h-7v-2zm2-5h5v2h-5V7z" /></svg> |             <path | ||||||
|           <span>{$_('contacts')}</span> |               fill="currentColor" | ||||||
|         </a> |               d="M2 4h2v16H2V4zm4 0h1v16H6V4zm2 0h2v16H8V4zm3 0h2v16h-2V4zm3 0h2v16h-2V4zm3 0h1v16h-1V4zm2 0h3v16h-3V4z" /></svg> | ||||||
|       {/if} |           <span>Scans</span> | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes('STATION:GET')} |         </a> | ||||||
|         <a |       {/if} | ||||||
|           class:bg-gray-100={$router.path === '/scanstations/'} |       {#if store.state.jwtinfo.userdetails.permissions.includes('CONTACT:GET')} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |         <a | ||||||
|           href="/scanstations/"> |           class:bg-gray-100={$router.path === '/contacts/'} | ||||||
|           <svg |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |           href="/contacts/"> | ||||||
|             fill="currentColor" |           <svg | ||||||
|             width="24" |             fill="currentColor" | ||||||
|             height="24" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|             viewBox="0 0 24 24" |             xmlns="http://www.w3.org/2000/svg" | ||||||
|             xmlns="http://www.w3.org/2000/svg"><path |             viewBox="0 0 24 24" | ||||||
|               fill="none" |             width="24" | ||||||
|               d="M0 0h24v24H0z" /> |             height="24"><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|             <path |             <path | ||||||
|               fill="currentColor" |               d="M2 22a8 8 0 1 1 16 0H2zm8-9c-3.315 0-6-2.685-6-6s2.685-6 6-6 6 2.685 6 6-2.685 6-6 6zm10 4h4v2h-4v-2zm-3-5h7v2h-7v-2zm2-5h5v2h-5V7z" /></svg> | ||||||
|               d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" /></svg> |           <span>{$_('contacts')}</span> | ||||||
|           <span>{$_('scanstations')}</span> |         </a> | ||||||
|         </a> |       {/if} | ||||||
|       {/if} |       {#if store.state.jwtinfo.userdetails.permissions.includes('STATION:GET')} | ||||||
|       <a |         <a | ||||||
|         class:bg-gray-100={$router.path === '/settings/'} |           class:bg-gray-100={$router.path === '/scanstations/'} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         href="/settings/"> |           href="/scanstations/"> | ||||||
|         <svg |           <svg | ||||||
|           class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|           xmlns="http://www.w3.org/2000/svg" |             fill="currentColor" | ||||||
|           viewBox="0 0 20 20" |             width="24" | ||||||
|           fill="currentColor"> |             height="24" | ||||||
|           <path |             viewBox="0 0 24 24" | ||||||
|             fill-rule="evenodd" |             xmlns="http://www.w3.org/2000/svg"><path | ||||||
|             d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z" |               fill="none" | ||||||
|             clip-rule="evenodd" /> |               d="M0 0h24v24H0z" /> | ||||||
|         </svg> |             <path | ||||||
|         <span>{$_('settings')}</span> |               fill="currentColor" | ||||||
|       </a> |               d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" /></svg> | ||||||
|       <a |           <span>{$_('scanstations')}</span> | ||||||
|         class:bg-gray-100={$router.path === '/about/'} |         </a> | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |       {/if} | ||||||
|         href="/about/"> |       <a | ||||||
|         <svg |         class:bg-gray-100={$router.path === '/settings/'} | ||||||
|           class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|           xmlns="http://www.w3.org/2000/svg" |         href="/settings/"> | ||||||
|           fill="none" |         <svg | ||||||
|           stroke="currentColor" |           class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|           stroke-width="2" |           xmlns="http://www.w3.org/2000/svg" | ||||||
|           stroke-linecap="round" |           viewBox="0 0 20 20" | ||||||
|           stroke-linejoin="round" |           fill="currentColor"> | ||||||
|           viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" /> |           <path | ||||||
|           <path d="M12 16v-4M12 8h.01" /></svg> |             fill-rule="evenodd" | ||||||
|         <span>{$_('about')}</span> |             d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z" | ||||||
|       </a> |             clip-rule="evenodd" /> | ||||||
|       <span |         </svg> | ||||||
|         tabindex="0" |         <span>{$_('settings')}</span> | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" |       </a> | ||||||
|         on:click={() => { |       <a | ||||||
|           AuthService.authControllerLogout(); |         class:bg-gray-100={$router.path === '/about/'} | ||||||
|           logout(); |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|         }}> |         href="/about/"> | ||||||
|         <svg |         <svg | ||||||
|           class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" |           class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|           fill="currentColor" |           xmlns="http://www.w3.org/2000/svg" | ||||||
|           width="24" |           fill="none" | ||||||
|           height="24" |           stroke="currentColor" | ||||||
|           xmlns="http://www.w3.org/2000/svg" |           stroke-width="2" | ||||||
|           viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z" /> |           stroke-linecap="round" | ||||||
|           <path |           stroke-linejoin="round" | ||||||
|             d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2a9.985 9.985 0 0 1 8 4h-2.71a8 8 0 1 0 .001 12h2.71A9.985 9.985 0 0 1 12 22zm7-6v-3h-8v-2h8V8l5 4-5 4z" /></svg> |           viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" /> | ||||||
|         <span>{$_('logout')}</span> |           <path d="M12 16v-4M12 8h.01" /></svg> | ||||||
|       </span> |         <span>{$_('about')}</span> | ||||||
|     </nav> |       </a> | ||||||
|   </nav> |       <span | ||||||
|   <div class="ml-0 transition md:ml-60"> |         tabindex="0" | ||||||
|     <header |         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | ||||||
|       on:click={() => { |         on:click={() => { | ||||||
|         navOpen = true; |           AuthService.authControllerLogout(); | ||||||
|       }} |           logout(); | ||||||
|       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"> |         <svg | ||||||
|         <span class="sr-only">Menu</span><svg |           class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | ||||||
|           class="w-4 h-4" |           fill="currentColor" | ||||||
|           xmlns="http://www.w3.org/2000/svg" |           width="24" | ||||||
|           viewBox="0 0 20 20" |           height="24" | ||||||
|           fill="currentcolor"><path |           xmlns="http://www.w3.org/2000/svg" | ||||||
|             fill-rule="evenodd" |           viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|             d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4A1 1 0 013 5zm0 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" |           <path | ||||||
|             clip-rule="evenodd" /></svg></button> |             d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2a9.985 9.985 0 0 1 8 4h-2.71a8 8 0 1 0 .001 12h2.71A9.985 9.985 0 0 1 12 22zm7-6v-3h-8v-2h8V8l5 4-5 4z" /></svg> | ||||||
|     </header> |         <span>{$_('logout')}</span> | ||||||
|     <slot> |       </span> | ||||||
|       <NoComponentLoaded /> |     </nav> | ||||||
|     </slot> |   </nav> | ||||||
|   </div> |   <div class="ml-0 transition md:ml-60"> | ||||||
|   <div |     <header | ||||||
|     on:click={() => { |       on:click={() => { | ||||||
|       navOpen = false; |         navOpen = true; | ||||||
|     }} |       }} | ||||||
|     class:hidden={!navOpen} |       class="flex items-center justify-between w-full px-4 bg-white border-b h-14 md:hidden"> | ||||||
|     class="fixed inset-0 z-10 w-screen h-screen bg-black bg-opacity-25 md:hidden" /> |       <button class="block btn btn-light md:hidden"> | ||||||
| </section> |         <span class="sr-only">Menu</span><svg | ||||||
|  |           class="w-4 h-4" | ||||||
|  |           xmlns="http://www.w3.org/2000/svg" | ||||||
|  |           viewBox="0 0 20 20" | ||||||
|  |           fill="currentcolor"><path | ||||||
|  |             fill-rule="evenodd" | ||||||
|  |             d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4A1 1 0 013 5zm0 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" | ||||||
|  |             clip-rule="evenodd" /></svg></button> | ||||||
|  |     </header> | ||||||
|  |     <slot> | ||||||
|  |       <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" /> | ||||||
|  | </section> | ||||||
|   | |||||||
| @@ -16,8 +16,7 @@ | |||||||
|       - |       - | ||||||
|       {$_('dashboard-greeting')}, |       {$_('dashboard-greeting')}, | ||||||
|       <span |       <span | ||||||
|         class="text-blue-500">{store.state.jwtinfo.userdetails.firstname}</span> |         class="text-blue-500">{store.state.jwtinfo.userdetails.firstname} {store.state.jwtinfo.userdetails.lastname}</span></span> | ||||||
|       👋</span> |  | ||||||
|   </h1> |   </h1> | ||||||
|   <StatCards /> |   <StatCards /> | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ | |||||||
|  |  | ||||||
| <div class="text-center items-center justify-center"> | <div class="text-center items-center justify-center"> | ||||||
|   <p class="mb-16 text-lg text-gray-500"> |   <p class="mb-16 text-lg text-gray-500"> | ||||||
|     <img class="w-full" style="height:15rem" src={donations_empty} alt="" /> |     <img class="m-auto" style="height:15rem" src={donations_empty} alt="" /> | ||||||
|     <span class="font-bold">There are no donations yet</span><br /> |     <span class="font-bold">{$_('there-are-no-donations-yet')}</span><br /> | ||||||
|     <span>add your fist donation</span> |     <span>{$_('add-your-fist-donation')}</span> | ||||||
|   </p> |   </p> | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -74,20 +74,12 @@ | |||||||
|                 .toLowerCase() |                 .toLowerCase() | ||||||
|                 .includes( |                 .includes( | ||||||
|                   searchvalue.toLowerCase() |                   searchvalue.toLowerCase() | ||||||
|                 ) || donation.donor.middlename |                 ) ||  donation.donor.lastname | ||||||
|                   .toLowerCase() |  | ||||||
|                   .includes( |  | ||||||
|                     searchvalue.toLowerCase() |  | ||||||
|                   ) || donation.donor.lastname |  | ||||||
|                   .toLowerCase() |                   .toLowerCase() | ||||||
|                   .includes( |                   .includes( | ||||||
|                     searchvalue.toLowerCase() |                     searchvalue.toLowerCase() | ||||||
|                   ) || donation.runner?.firstname |                   ) || donation.runner?.firstname | ||||||
|                   .toLowerCase() |                   .toLowerCase() | ||||||
|                   .includes( |  | ||||||
|                     searchvalue.toLowerCase() |  | ||||||
|                   ) || donation.runner?.middlename |  | ||||||
|                   .toLowerCase() |  | ||||||
|                   .includes( |                   .includes( | ||||||
|                     searchvalue.toLowerCase() |                     searchvalue.toLowerCase() | ||||||
|                   ) || donation.runner?.lastname |                   ) || donation.runner?.lastname | ||||||
|   | |||||||
| @@ -88,11 +88,7 @@ | |||||||
|                 .toLowerCase() |                 .toLowerCase() | ||||||
|                 .includes( |                 .includes( | ||||||
|                   searchvalue.toLowerCase() |                   searchvalue.toLowerCase() | ||||||
|                 ) || donor.middlename |                 ) ||  donor.lastname | ||||||
|                   .toLowerCase() |  | ||||||
|                   .includes( |  | ||||||
|                     searchvalue.toLowerCase() |  | ||||||
|                   ) || donor.lastname |  | ||||||
|                   .toLowerCase() |                   .toLowerCase() | ||||||
|                   .includes( |                   .includes( | ||||||
|                     searchvalue.toLowerCase() |                     searchvalue.toLowerCase() | ||||||
|   | |||||||
| @@ -189,34 +189,5 @@ | |||||||
|         </li> |         </li> | ||||||
|       </ul> |       </ul> | ||||||
|     </div> |     </div> | ||||||
|     <h2 class="mt-4 text-4xl font-display font-semibold md:text-5xl"> |  | ||||||
|       {$_('faq')} |  | ||||||
|     </h2> |  | ||||||
|     <div class="mt-6 border-t-2 border-gray-100 pt-10"> |  | ||||||
|       <dl class="md:grid md:grid-cols-2 md:gap-8"> |  | ||||||
|         <div> |  | ||||||
|           <div> |  | ||||||
|             <dt class="text-lg leading-6 font-medium">Q</dt> |  | ||||||
|             <dd class="mt-2"> |  | ||||||
|               <p class="text-base text-gray-500">A</p> |  | ||||||
|             </dd> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|         <div class="mt-12 sm:mt-0"> |  | ||||||
|           <div id="team-pricing"> |  | ||||||
|             <dt class="text-lg leading-6 font-medium">Q</dt> |  | ||||||
|             <dd class="mt-2"> |  | ||||||
|               <p class="text-base text-gray-500">A</p> |  | ||||||
|             </dd> |  | ||||||
|           </div> |  | ||||||
|           <div class="mt-12"> |  | ||||||
|             <dt class="text-lg leading-6 font-medium">Q</dt> |  | ||||||
|             <dd class="mt-2"> |  | ||||||
|               <p class="text-base text-gray-500">A</p> |  | ||||||
|             </dd> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </dl> |  | ||||||
|     </div> |  | ||||||
|   </div> |   </div> | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -32,6 +32,8 @@ | |||||||
|       target="_blank" |       target="_blank" | ||||||
|       rel="noopener, noreferrer" |       rel="noopener, noreferrer" | ||||||
|       href="https://git.odit.services/lfk/frontend/src/tag/{releaseinfo}">{releaseinfo}</a> |       href="https://git.odit.services/lfk/frontend/src/tag/{releaseinfo}">{releaseinfo}</a> | ||||||
|  |       - | ||||||
|  |     <a class="underline" href="https://docs.lauf-fuer-kaya.de" target="_blank">{$_('documentation')}</a> | ||||||
|     - |     - | ||||||
|     <a class="underline" href="/privacy">{$_('privacy')}</a> |     <a class="underline" href="/privacy">{$_('privacy')}</a> | ||||||
|     - |     - | ||||||
|   | |||||||
| @@ -6,13 +6,15 @@ | |||||||
|   let html = ""; |   let html = ""; | ||||||
|   async function load() { |   async function load() { | ||||||
|     let md = await fetch("/imprint_" + getLocaleFromNavigator() + ".md"); |     let md = await fetch("/imprint_" + getLocaleFromNavigator() + ".md"); | ||||||
|     if((await md.text()).includes("<meta")){ |     let text = (await md.text()).toString(); | ||||||
|  |     if(text.includes("<meta")){ | ||||||
|       md.ok=false |       md.ok=false | ||||||
|     } |     } | ||||||
|     if (!md.ok) { |     if (!md.ok) { | ||||||
|       md = await fetch("/imprint_en.md"); |       md = await fetch("/imprint_en.md"); | ||||||
|  |       text = await md.text(); | ||||||
|     } |     } | ||||||
|     html = marked(await md.text()); |     html = marked(text); | ||||||
|   } |   } | ||||||
|   const promise = load(); |   const promise = load(); | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -6,13 +6,15 @@ | |||||||
|   let html = ""; |   let html = ""; | ||||||
|   async function load() { |   async function load() { | ||||||
|     let md = await fetch("/privacy_" + getLocaleFromNavigator() + ".md"); |     let md = await fetch("/privacy_" + getLocaleFromNavigator() + ".md"); | ||||||
|     if((await md.text()).includes("<meta")){ |     let text = (await md.text()).toString(); | ||||||
|  |     if(text.includes("<meta")){ | ||||||
|       md.ok=false |       md.ok=false | ||||||
|     } |     } | ||||||
|     if (!md.ok) { |     if (!md.ok) { | ||||||
|       md = await fetch("/privacy_en.md"); |       md = await fetch("/privacy_en.md"); | ||||||
|  |       text = await md.text(); | ||||||
|     } |     } | ||||||
|     html = marked(await md.text()); |     html = marked(text); | ||||||
|   } |   } | ||||||
|   const promise = load(); |   const promise = load(); | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -10,6 +10,8 @@ | |||||||
|   import ImportRunnerModal from "../runners/ImportRunnerModal.svelte"; |   import ImportRunnerModal from "../runners/ImportRunnerModal.svelte"; | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; |   import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   import Select from "svelte-select"; |   import Select from "svelte-select"; | ||||||
|  |   import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | ||||||
|  |   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|   $: delete_triggered = false; |   $: delete_triggered = false; | ||||||
|   $: address_valid_or_none = |   $: address_valid_or_none = | ||||||
|     (isAddress1Valid && iszipcodevalid && iscityvalid) || |     (isAddress1Valid && iszipcodevalid && iscityvalid) || | ||||||
| @@ -26,7 +28,9 @@ | |||||||
|   $: isAddress1Valid = editable.address?.address1?.trim().length !== 0; |   $: isAddress1Valid = editable.address?.address1?.trim().length !== 0; | ||||||
|   $: iszipcodevalid = editable.address?.postalcode?.trim().length !== 0; |   $: iszipcodevalid = editable.address?.postalcode?.trim().length !== 0; | ||||||
|   $: iscityvalid = editable.address?.city?.trim().length !== 0; |   $: iscityvalid = editable.address?.city?.trim().length !== 0; | ||||||
|   $: sponsoring_contracts_download_open = false; |   $: sponsoring_contracts_show = true; | ||||||
|  |   $: cards_show = true; | ||||||
|  |   $: generate_orgs = [original_object]; | ||||||
|   const getContactLabel = (option) => |   const getContactLabel = (option) => | ||||||
|     option.firstname + " " + (option.middlename || "") + " " + option.lastname; |     option.firstname + " " + (option.middlename || "") + " " + option.lastname; | ||||||
|   const promise = RunnerOrganizationService.runnerOrganizationControllerGetOne( |   const promise = RunnerOrganizationService.runnerOrganizationControllerGetOne( | ||||||
| @@ -60,14 +64,6 @@ | |||||||
|   }); |   }); | ||||||
|   let modal_open = false; |   let modal_open = false; | ||||||
|   let delete_org = {}; |   let delete_org = {}; | ||||||
|   document.addEventListener("click", function (e) { |  | ||||||
|     if ( |  | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown" && |  | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown:menu" |  | ||||||
|     ) { |  | ||||||
|       sponsoring_contracts_download_open = false; |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
|   function deleteOrganization() { |   function deleteOrganization() { | ||||||
|     RunnerOrganizationService.runnerOrganizationControllerRemove( |     RunnerOrganizationService.runnerOrganizationControllerRemove( | ||||||
|       original_object.id, |       original_object.id, | ||||||
| @@ -115,55 +111,6 @@ | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   export let import_modal_open = false; |   export let import_modal_open = false; | ||||||
|   async function generateSponsoringContract(locale) { |  | ||||||
|     sponsoring_contracts_download_open = false; |  | ||||||
|     const runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners( |  | ||||||
|       original_object.id |  | ||||||
|     ); |  | ||||||
|     const toast = Toastify({ |  | ||||||
|       text: $_("generating-pdf"), |  | ||||||
|       duration: -1, |  | ||||||
|     }).showToast(); |  | ||||||
|     fetch( |  | ||||||
|       `https://dev.lauf-fuer-kaya.de/documents/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_" + original_object.name + ".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) => {}); |  | ||||||
|   } |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <ImportRunnerModal | <ImportRunnerModal | ||||||
| @@ -182,64 +129,12 @@ | |||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> |     <div class="mb-8 text-3xl font-extrabold leading-tight"> | ||||||
|       {original_object.name} |       {original_object.name} | ||||||
|       <span data-id="org_actions_${editable.id}"> |       <span data-id="org_actions_${editable.id}"> | ||||||
|         <div id="sponsoring:dropdown" class="relative inline-block"> |         <GenerateSponsoringContracts | ||||||
|           <div> |           bind:sponsoring_contracts_show | ||||||
|             <button |           bind:generate_orgs /> | ||||||
|               on:click={() => { |         <GenerateRunnerCards | ||||||
|                 sponsoring_contracts_download_open = !sponsoring_contracts_download_open; |           bind:cards_show | ||||||
|               }} |           bind:generate_orgs /> | ||||||
|               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-sponsoring-contracts')} |  | ||||||
|               <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 sponsoring_contracts_download_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="sponsoring: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={() => { |  | ||||||
|                     generateSponsoringContract('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 inline-flex" |  | ||||||
|                   role="menuitem"> |  | ||||||
|                   {$_('german')} |  | ||||||
|                 </button> |  | ||||||
|                 <button |  | ||||||
|                   on:click={() => { |  | ||||||
|                     generateSponsoringContract('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 inline-flex" |  | ||||||
|                   role="menuitem"> |  | ||||||
|                   {$_('english')} |  | ||||||
|                 </button> |  | ||||||
|               </div> |  | ||||||
|             </div> |  | ||||||
|           {/if} |  | ||||||
|         </div> |  | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')} |         {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')} | ||||||
|           <button |           <button | ||||||
|             on:click={() => { |             on:click={() => { | ||||||
|   | |||||||
| @@ -1,318 +1,212 @@ | |||||||
| <script> | <script> | ||||||
|   import { getLocaleFromNavigator, _ } from "svelte-i18n"; |   import { getLocaleFromNavigator, _ } from "svelte-i18n"; | ||||||
|   let modal_open = false; |   import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | ||||||
|   let delete_org = {}; |   let modal_open = false; | ||||||
|   import { RunnerOrganizationService } from "@odit/lfk-client-js"; |   let delete_org = {}; | ||||||
|   import store from "../../store"; |   import { RunnerOrganizationService } from "@odit/lfk-client-js"; | ||||||
|   import OrgsEmptyState from "./OrgsEmptyState.svelte"; |   import store from "../../store"; | ||||||
|   import Toastify from "toastify-js"; |   import OrgsEmptyState from "./OrgsEmptyState.svelte"; | ||||||
|   import ConfirmOrgDeletion from "./ConfirmOrgDeletion.svelte"; |   import Toastify from "toastify-js"; | ||||||
|   $: searchvalue = ""; |   import ConfirmOrgDeletion from "./ConfirmOrgDeletion.svelte"; | ||||||
|   $: active_deletes = []; |   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|   $: sponsoring_contracts_download_open = false; |   $: searchvalue = ""; | ||||||
|   export let current_organizations = []; |   $: active_deletes = []; | ||||||
|  |   $: sponsoring_contracts_show = current_organizations.some((r) => r.is_selected === true); | ||||||
|   const promise = RunnerOrganizationService.runnerOrganizationControllerGetAll().then( |   $: cards_show = current_organizations.some((r) => r.is_selected === true); | ||||||
|     (val) => { |   $: generate_orgs = current_organizations.filter((r) => r.is_selected === true); | ||||||
|       current_organizations = val; |   export let current_organizations = []; | ||||||
|     } |  | ||||||
|   ); |   const promise = RunnerOrganizationService.runnerOrganizationControllerGetAll().then( | ||||||
|  |     (val) => { | ||||||
|   document.addEventListener("click", function (e) { |       current_organizations = val; | ||||||
|     if ( |     } | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown" && |   ); | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown:menu" | </script> | ||||||
|     ) { |  | ||||||
|       sponsoring_contracts_download_open = false; | <ConfirmOrgDeletion | ||||||
|     } |   on:cancelDelete={(event) => { | ||||||
|   }); |     modal_open = false; | ||||||
|  |     active_deletes[event.detail.id] = false; | ||||||
|   async function generateSponsoringContract(locale) { |   }} | ||||||
|     sponsoring_contracts_download_open = false; |   bind:modal_open | ||||||
|     const orgs = current_organizations.filter((r) => r.is_selected === true); |   bind:delete_org /> | ||||||
|     const toast = Toastify({ | {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANIZATION:GET')} | ||||||
|       text: $_("generating-pdfs"), |   {#await promise} | ||||||
|       duration: -1, |     <div | ||||||
|     }).showToast(); |       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|     let count = 0; |       role="alert"> | ||||||
|     for await (const o of orgs) { |       <p class="font-bold">{$_('organizations-are-being-loaded')}</p> | ||||||
|       const runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners( |       <p class="text-sm">{$_('this-might-take-a-moment')}</p> | ||||||
|         o.id |     </div> | ||||||
|       ); |   {:then} | ||||||
|       fetch( |     {#if current_organizations.length === 0} | ||||||
|         `https://dev.lauf-fuer-kaya.de/documents/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, |       <OrgsEmptyState /> | ||||||
|         { |     {:else} | ||||||
|           method: "POST", |       <input | ||||||
|           headers: { |         type="search" | ||||||
|             "Content-Type": "application/json", |         bind:value={searchvalue} | ||||||
|           }, |         placeholder={$_('datatable.search')} | ||||||
|           body: JSON.stringify(runners), |         aria-label={$_('datatable.search')} | ||||||
|         } |         class="gridjs-input gridjs-search-input mb-4" /> | ||||||
|       ) |       <div class="h-12"> | ||||||
|         .then((response) => { |         <GenerateSponsoringContracts | ||||||
|           if (response.status != "200") { |             bind:sponsoring_contracts_show | ||||||
|             toast.hideToast(); |             bind:generate_orgs /> | ||||||
|             Toastify({ |         <GenerateRunnerCards | ||||||
|               text: $_("pdf-generation-failed"), |             bind:cards_show | ||||||
|               duration: 3500, |             bind:generate_orgs /> | ||||||
|               backgroundColor: |       </div> | ||||||
|                 "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", |       <div | ||||||
|             }).showToast(); |         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> | ||||||
|           } else { |         <table class="divide-y divide-gray-200 w-full"> | ||||||
|             return response.blob(); |           <thead class="bg-gray-50"> | ||||||
|           } |             <tr> | ||||||
|         }) |               <th | ||||||
|         .then((blob) => { |                 scope="col" | ||||||
|           count++; |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|           const url = window.URL.createObjectURL(blob); |                 <span | ||||||
|           let a = document.createElement("a"); |                   on:click={() => { | ||||||
|           a.href = url; |                     const newstate = !current_organizations.some((r) => r.is_selected === true); | ||||||
|           a.download = "Sponsorings_" + o.name + ".pdf"; |                     current_organizations = current_organizations.map((r) => { | ||||||
|           document.body.appendChild(a); |                       r.is_selected = newstate; | ||||||
|           a.click(); |                       return r; | ||||||
|           a.remove(); |                     }); | ||||||
|           if (count === orgs.length) { |                   }} | ||||||
|             toast.hideToast(); |                   class="underline cursor-pointer select-none">{#if current_organizations.some((r) => r.is_selected === true)} | ||||||
|             Toastify({ |                     {$_('deselect-all')} | ||||||
|               text: $_("pdfs-successfully-generated"), |                   {:else}{$_('select-all')}{/if} | ||||||
|               duration: 3500, |                 </span> | ||||||
|               backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", |               </th> | ||||||
|             }).showToast(); |               <th | ||||||
|           } |                 scope="col" | ||||||
|         }) |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|         .catch((err) => {}); |                 {$_('name')} | ||||||
|     } |               </th> | ||||||
|   } |               <th | ||||||
| </script> |                 scope="col" | ||||||
|  |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
| <ConfirmOrgDeletion |                 {$_('address')} | ||||||
|   on:cancelDelete={(event) => { |               </th> | ||||||
|     modal_open = false; |               <th | ||||||
|     active_deletes[event.detail.id] = false; |                 scope="col" | ||||||
|   }} |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|   bind:modal_open |                 {$_('contact')} | ||||||
|   bind:delete_org /> |               </th> | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANIZATION:GET')} |               <th scope="col" class="relative px-6 py-3"> | ||||||
|   {#await promise} |                 <span class="sr-only">{$_('action')}</span> | ||||||
|     <div |               </th> | ||||||
|       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" |             </tr> | ||||||
|       role="alert"> |           </thead> | ||||||
|       <p class="font-bold">{$_('organizations-are-being-loaded')}</p> |           <tbody class="divide-y divide-gray-200"> | ||||||
|       <p class="text-sm">{$_('this-might-take-a-moment')}</p> |             {#each current_organizations as o} | ||||||
|     </div> |               {#if Object.values(o) | ||||||
|   {:then} |                 .toString() | ||||||
|     {#if current_organizations.length === 0} |                 .toLowerCase() | ||||||
|       <OrgsEmptyState /> |                 .includes(searchvalue)} | ||||||
|     {:else} |                 <tr data-rowid="org_{o.id}"> | ||||||
|       <input |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|         type="search" |                     <input | ||||||
|         bind:value={searchvalue} |                       bind:checked={o.is_selected} | ||||||
|         placeholder={$_('datatable.search')} |                       type="checkbox" | ||||||
|         aria-label={$_('datatable.search')} |                       class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" /> | ||||||
|         class="gridjs-input gridjs-search-input mb-4" /> |                   </td> | ||||||
|       <div class="h-12"> |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|         {#if current_organizations.some((r) => r.is_selected === true)} |                     <div class="flex items-center"> | ||||||
|         <div id="sponsoring:dropdown" class="relative inline-block"> |                       <div class="ml-4"> | ||||||
|           <div> |                         <div class="text-sm font-medium text-gray-900"> | ||||||
|             <button |                           {o.name} | ||||||
|               on:click={() => { |                         </div> | ||||||
|                 sponsoring_contracts_download_open = !sponsoring_contracts_download_open; |                       </div> | ||||||
|               }} |                     </div> | ||||||
|               type="button" |                   </td> | ||||||
|               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" |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|               id="options-menu" |                     <div class="flex items-center"> | ||||||
|               aria-haspopup="true" |                       <div class="ml-4"> | ||||||
|               aria-expanded="true"> |                         <div class="text-sm font-medium text-gray-900"> | ||||||
|               {$_('generate-sponsoring-contracts')} |                           {#if o.address.address1 !== null} | ||||||
|               <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> |                             {o.address.address1}<br /> | ||||||
|             </button> |                             {o.address.address2 || ''}<br /> | ||||||
|           </div> |                             {o.address.postalcode} | ||||||
|           {#if sponsoring_contracts_download_open} |                             {o.address.city} | ||||||
|             <div |                             {o.address.country} | ||||||
|               class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5" |                           {/if} | ||||||
|               id="sponsoring:dropdown:menu"> |                         </div> | ||||||
|               <div |                       </div> | ||||||
|                 class="py-1" |                     </div> | ||||||
|                 role="menu" |                   </td> | ||||||
|                 aria-orientation="vertical" |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                 aria-labelledby="options-menu"> |                     <div class="flex items-center"> | ||||||
|                 <span |                       <div class="ml-4"> | ||||||
|                   class="block w-full text-left px-4 py-2 text-sm text-gray-700">{$_('select-language')}</span> |                         <div class="text-sm font-medium text-gray-900"> | ||||||
|                 <button |                           {#if o.contact} | ||||||
|                   on:click={() => { |                             <a | ||||||
|                     generateSponsoringContract('de'); |                               href="../contacts/{o.contact.id}" | ||||||
|                   }} |                               class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{o.contact.firstname} | ||||||
|                   type="submit" |                               {o.contact.middlename || ''} | ||||||
|                   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 inline-flex" |                               {o.contact.lastname}</a> | ||||||
|                   role="menuitem"> |                           {:else}{$_('no-contact-specified')}{/if} | ||||||
|                   {$_('german')} |                         </div> | ||||||
|                 </button> |                       </div> | ||||||
|                 <button |                     </div> | ||||||
|                   on:click={() => { |                   </td> | ||||||
|                     generateSponsoringContract('en'); |                   {#if active_deletes[o.id] === true} | ||||||
|                   }} |                     <td | ||||||
|                   type="submit" |                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|                   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 inline-flex" |                       <button | ||||||
|                   role="menuitem"> |                         on:click={() => { | ||||||
|                   {$_('english')} |                           active_deletes[o.id] = false; | ||||||
|                 </button> |                         }} | ||||||
|               </div> |                         tabindex="0" | ||||||
|             </div> |                         class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button> | ||||||
|           {/if} |                       <button | ||||||
|         </div> |                         on:click={() => { | ||||||
|         {/if} |                           RunnerOrganizationService.runnerOrganizationControllerRemove(o.id, false) | ||||||
|       </div> |                             .then((resp) => { | ||||||
|       <div |                               current_organizations = current_organizations.filter((obj) => obj.id !== o.id); | ||||||
|         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> |                               Toastify({ | ||||||
|         <table class="divide-y divide-gray-200 w-full"> |                                 text: 'Organization deleted', | ||||||
|           <thead class="bg-gray-50"> |                                 duration: 500, | ||||||
|             <tr> |                                 backgroundColor: | ||||||
|               <th |                                   'linear-gradient(to right, #00b09b, #96c93d)', | ||||||
|                 scope="col" |                               }).showToast(); | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |                             }) | ||||||
|                 <span |                             .catch((err) => { | ||||||
|                   on:click={() => { |                               modal_open = true; | ||||||
|                     const newstate = !current_organizations.some((r) => r.is_selected === true); |                               delete_org = o; | ||||||
|                     current_organizations = current_organizations.map((r) => { |                             }); | ||||||
|                       r.is_selected = newstate; |                         }} | ||||||
|                       return r; |                         tabindex="0" | ||||||
|                     }); |                         class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button> | ||||||
|                   }} |                     </td> | ||||||
|                   class="underline cursor-pointer select-none">{#if current_organizations.some((r) => r.is_selected === true)} |                   {:else} | ||||||
|                     {$_('deselect-all')} |                     <td | ||||||
|                   {:else}{$_('select-all')}{/if} |                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|                 </span> |                       <a | ||||||
|               </th> |                         href="./{o.id}" | ||||||
|               <th |                         class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a> | ||||||
|                 scope="col" |                       {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANIZATION:DELETE')} | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |                         <button | ||||||
|                 {$_('name')} |                           on:click={() => { | ||||||
|               </th> |                             active_deletes[o.id] = true; | ||||||
|               <th |                           }} | ||||||
|                 scope="col" |                           tabindex="0" | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button> | ||||||
|                 {$_('address')} |                       {/if} | ||||||
|               </th> |                     </td> | ||||||
|               <th |                   {/if} | ||||||
|                 scope="col" |                 </tr> | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |               {/if} | ||||||
|                 {$_('contact')} |             {/each} | ||||||
|               </th> |           </tbody> | ||||||
|               <th scope="col" class="relative px-6 py-3"> |         </table> | ||||||
|                 <span class="sr-only">{$_('action')}</span> |       </div> | ||||||
|               </th> |     {/if} | ||||||
|             </tr> |   {:catch error} | ||||||
|           </thead> |     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> | ||||||
|           <tbody class="divide-y divide-gray-200"> |       <span class="inline-block align-middle mr-8"> | ||||||
|             {#each current_organizations as o} |         <b class="capitalize">{$_('general_promise_error')}</b> | ||||||
|               {#if Object.values(o) |         {error} | ||||||
|                 .toString() |       </span> | ||||||
|                 .toLowerCase() |     </div> | ||||||
|                 .includes(searchvalue)} |   {/await} | ||||||
|                 <tr data-rowid="org_{o.id}"> | {/if} | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                     <input |  | ||||||
|                       bind:checked={o.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"> |  | ||||||
|                       <div class="ml-4"> |  | ||||||
|                         <div class="text-sm font-medium text-gray-900"> |  | ||||||
|                           {o.name} |  | ||||||
|                         </div> |  | ||||||
|                       </div> |  | ||||||
|                     </div> |  | ||||||
|                   </td> |  | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                     <div class="flex items-center"> |  | ||||||
|                       <div class="ml-4"> |  | ||||||
|                         <div class="text-sm font-medium text-gray-900"> |  | ||||||
|                           {#if o.address.address1 !== null} |  | ||||||
|                             {o.address.address1}<br /> |  | ||||||
|                             {o.address.address2 || ''}<br /> |  | ||||||
|                             {o.address.postalcode} |  | ||||||
|                             {o.address.city} |  | ||||||
|                             {o.address.country} |  | ||||||
|                           {/if} |  | ||||||
|                         </div> |  | ||||||
|                       </div> |  | ||||||
|                     </div> |  | ||||||
|                   </td> |  | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                     <div class="flex items-center"> |  | ||||||
|                       <div class="ml-4"> |  | ||||||
|                         <div class="text-sm font-medium text-gray-900"> |  | ||||||
|                           {#if o.contact} |  | ||||||
|                             <a |  | ||||||
|                               href="../contacts/{o.contact.id}" |  | ||||||
|                               class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{o.contact.firstname} |  | ||||||
|                               {o.contact.middlename || ''} |  | ||||||
|                               {o.contact.lastname}</a> |  | ||||||
|                           {:else}{$_('no-contact-specified')}{/if} |  | ||||||
|                         </div> |  | ||||||
|                       </div> |  | ||||||
|                     </div> |  | ||||||
|                   </td> |  | ||||||
|                   {#if active_deletes[o.id] === true} |  | ||||||
|                     <td |  | ||||||
|                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> |  | ||||||
|                       <button |  | ||||||
|                         on:click={() => { |  | ||||||
|                           active_deletes[o.id] = false; |  | ||||||
|                         }} |  | ||||||
|                         tabindex="0" |  | ||||||
|                         class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button> |  | ||||||
|                       <button |  | ||||||
|                         on:click={() => { |  | ||||||
|                           RunnerOrganizationService.runnerOrganizationControllerRemove(o.id, false) |  | ||||||
|                             .then((resp) => { |  | ||||||
|                               current_organizations = current_organizations.filter((obj) => obj.id !== o.id); |  | ||||||
|                               Toastify({ |  | ||||||
|                                 text: 'Organization deleted', |  | ||||||
|                                 duration: 500, |  | ||||||
|                                 backgroundColor: |  | ||||||
|                                   'linear-gradient(to right, #00b09b, #96c93d)', |  | ||||||
|                               }).showToast(); |  | ||||||
|                             }) |  | ||||||
|                             .catch((err) => { |  | ||||||
|                               modal_open = true; |  | ||||||
|                               delete_org = o; |  | ||||||
|                             }); |  | ||||||
|                         }} |  | ||||||
|                         tabindex="0" |  | ||||||
|                         class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button> |  | ||||||
|                     </td> |  | ||||||
|                   {:else} |  | ||||||
|                     <td |  | ||||||
|                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> |  | ||||||
|                       <a |  | ||||||
|                         href="./{o.id}" |  | ||||||
|                         class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a> |  | ||||||
|                       {#if store.state.jwtinfo.userdetails.permissions.includes('ORGANIZATION:DELETE')} |  | ||||||
|                         <button |  | ||||||
|                           on:click={() => { |  | ||||||
|                             active_deletes[o.id] = true; |  | ||||||
|                           }} |  | ||||||
|                           tabindex="0" |  | ||||||
|                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button> |  | ||||||
|                       {/if} |  | ||||||
|                     </td> |  | ||||||
|                   {/if} |  | ||||||
|                 </tr> |  | ||||||
|               {/if} |  | ||||||
|             {/each} |  | ||||||
|           </tbody> |  | ||||||
|         </table> |  | ||||||
|       </div> |  | ||||||
|     {/if} |  | ||||||
|   {:catch error} |  | ||||||
|     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> |  | ||||||
|       <span class="inline-block align-middle mr-8"> |  | ||||||
|         <b class="capitalize">{$_('general_promise_error')}</b> |  | ||||||
|         {error} |  | ||||||
|       </span> |  | ||||||
|     </div> |  | ||||||
|   {/await} |  | ||||||
| {/if} |  | ||||||
|   | |||||||
							
								
								
									
										339
									
								
								src/components/pdf_generation/GenerateRunnerCards.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								src/components/pdf_generation/GenerateRunnerCards.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,339 @@ | |||||||
|  | <script> | ||||||
|  |     import { getLocaleFromNavigator, _ } from "svelte-i18n"; | ||||||
|  |     import { | ||||||
|  |         RunnerCardService, | ||||||
|  |         RunnerOrganizationService, | ||||||
|  |         RunnerTeamService, | ||||||
|  |     } from "@odit/lfk-client-js"; | ||||||
|  |     import Toastify from "toastify-js"; | ||||||
|  |     export let cards_show = false; | ||||||
|  |     export let generate_cards = []; | ||||||
|  |     export let generate_runners = []; | ||||||
|  |     export let generate_orgs = []; | ||||||
|  |     export let generate_teams = []; | ||||||
|  |     $: cards_dropdown_open = false; | ||||||
|  |     document.addEventListener("click", function (e) { | ||||||
|  |         if ( | ||||||
|  |             e.target.parentNode?.parentNode?.id != "cards:dropdown" && | ||||||
|  |             e.target.parentNode?.parentNode?.id != "cards:dropdown:menu" | ||||||
|  |         ) { | ||||||
|  |             cards_dropdown_open = false; | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     function generateRunnerCards(locale) { | ||||||
|  |         cards_dropdown_open = false; | ||||||
|  |  | ||||||
|  |         if (generate_orgs.length > 0) { | ||||||
|  |             generateOrgCards(locale); | ||||||
|  |         } else if (generate_teams.length > 0) { | ||||||
|  |             generateTeamCards(locale); | ||||||
|  |         } else if (generate_runners.length > 0) { | ||||||
|  |             generateRunnersCards(locale); | ||||||
|  |         } else { | ||||||
|  |             generateCards(locale); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function generateCards(locale) { | ||||||
|  |         const toast = Toastify({ | ||||||
|  |             text: $_("generating-pdf"), | ||||||
|  |             duration: -1, | ||||||
|  |         }).showToast(); | ||||||
|  |         fetch( | ||||||
|  |             `${config.baseurl}/documents/cards?locale=${locale}&download=true&key=${config.documentserver_key}`, | ||||||
|  |             { | ||||||
|  |                 method: "POST", | ||||||
|  |                 headers: { | ||||||
|  |                     "Content-Type": "application/json", | ||||||
|  |                 }, | ||||||
|  |                 body: JSON.stringify(generate_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.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); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async function generateRunnersCards(locale) { | ||||||
|  |         const toast = Toastify({ | ||||||
|  |             text: $_("generating-pdf"), | ||||||
|  |             duration: -1, | ||||||
|  |         }).showToast(); | ||||||
|  |         const current_cards = await RunnerCardService.runnerCardControllerGetAll(); | ||||||
|  |         let cards = []; | ||||||
|  |         for (let runner of generate_runners) { | ||||||
|  |             let card = current_cards.find((c) => c.runner?.id == runner.id); | ||||||
|  |             if (!card) { | ||||||
|  |                 card = await RunnerCardService.runnerCardControllerPost({ | ||||||
|  |                     runner: runner.id, | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             cards.push(card); | ||||||
|  |         } | ||||||
|  |         fetch( | ||||||
|  |             `${config.baseurl}/documents/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.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 generateTeamCards(locale) { | ||||||
|  |         const toast = Toastify({ | ||||||
|  |             text: $_("generating-pdfs"), | ||||||
|  |             duration: -1, | ||||||
|  |         }).showToast(); | ||||||
|  |         let count = 0; | ||||||
|  |         const current_cards = await RunnerCardService.runnerCardControllerGetAll(); | ||||||
|  |         for await (const t of generate_teams) { | ||||||
|  |             const 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); | ||||||
|  |             } | ||||||
|  |             fetch( | ||||||
|  |                 `${config.baseurl}/documents/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) => { | ||||||
|  |                     count++; | ||||||
|  |                     const url = window.URL.createObjectURL(blob); | ||||||
|  |                     let a = document.createElement("a"); | ||||||
|  |                     a.href = url; | ||||||
|  |                     a.download = "Sponsorings_" + t.name + ".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 generateOrgCards(locale) { | ||||||
|  |         const toast = Toastify({ | ||||||
|  |             text: $_("generating-pdf"), | ||||||
|  |             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 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); | ||||||
|  |             } | ||||||
|  |             fetch( | ||||||
|  |                 `${config.baseurl}/documents/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) => { | ||||||
|  |                     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) => {}); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if cards_show} | ||||||
|  |     <div id="cards:dropdown" class="relative inline-block"> | ||||||
|  |         <div> | ||||||
|  |             <button | ||||||
|  |                 on:click={() => { | ||||||
|  |                     cards_dropdown_open = !cards_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-runnercards')} | ||||||
|  |                 <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 cards_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="cards: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={() => { | ||||||
|  |                             generateRunnerCards('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={() => { | ||||||
|  |                             generateRunnerCards('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} | ||||||
							
								
								
									
										251
									
								
								src/components/pdf_generation/GenerateSponsoringContracts.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								src/components/pdf_generation/GenerateSponsoringContracts.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,251 @@ | |||||||
|  | <script> | ||||||
|  |     import { getLocaleFromNavigator, _ } from "svelte-i18n"; | ||||||
|  |     import { RunnerOrganizationService, RunnerTeamService } from "@odit/lfk-client-js"; | ||||||
|  |     import Toastify from "toastify-js"; | ||||||
|  |     export let sponsoring_contracts_show = false; | ||||||
|  |     export let generate_runners = []; | ||||||
|  |     export let generate_orgs = []; | ||||||
|  |     export let generate_teams = []; | ||||||
|  |     $: sponsoring_contracts_download_open = false; | ||||||
|  |     document.addEventListener("click", function (e) { | ||||||
|  |         if ( | ||||||
|  |             e.target.parentNode?.parentNode?.id != "sponsoring:dropdown" && | ||||||
|  |             e.target.parentNode?.parentNode?.id != "sponsoring:dropdown:menu" | ||||||
|  |         ) { | ||||||
|  |             sponsoring_contracts_download_open = false; | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     function generateSponsoringContract(locale) { | ||||||
|  |         sponsoring_contracts_download_open = false; | ||||||
|  |  | ||||||
|  |         if (generate_orgs.length > 0) { | ||||||
|  |             generateOrgContracts(locale); | ||||||
|  |         } else if (generate_teams.length > 0) { | ||||||
|  |             generateTeamContracts(locale); | ||||||
|  |         } else { | ||||||
|  |             generateRunnerContracts(locale); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async function generateTeamContracts(locale) { | ||||||
|  |         const toast = Toastify({ | ||||||
|  |             text: $_("generating-pdfs"), | ||||||
|  |             duration: -1, | ||||||
|  |         }).showToast(); | ||||||
|  |         let count = 0; | ||||||
|  |         for await (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}`, | ||||||
|  |                 { | ||||||
|  |                     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_" + t.name + ".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 generateOrgContracts(locale) { | ||||||
|  |         const toast = Toastify({ | ||||||
|  |             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}`, | ||||||
|  |                 { | ||||||
|  |                     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) => { | ||||||
|  |                     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) => {}); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function generateRunnerContracts(locale) { | ||||||
|  |         const toast = Toastify({ | ||||||
|  |             text: $_("generating-pdf"), | ||||||
|  |             duration: -1, | ||||||
|  |         }).showToast(); | ||||||
|  |         fetch( | ||||||
|  |             `${config.baseurl}/documents/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, | ||||||
|  |             { | ||||||
|  |                 method: "POST", | ||||||
|  |                 headers: { | ||||||
|  |                     "Content-Type": "application/json", | ||||||
|  |                 }, | ||||||
|  |                 body: JSON.stringify(generate_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 = "Sponsoring.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); | ||||||
|  |             }); | ||||||
|  |     } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if sponsoring_contracts_show} | ||||||
|  |     <div id="sponsoring:dropdown" class="relative inline-block"> | ||||||
|  |         <div> | ||||||
|  |             <button | ||||||
|  |                 on:click={() => { | ||||||
|  |                     sponsoring_contracts_download_open = !sponsoring_contracts_download_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-sponsoring-contracts')} | ||||||
|  |                 <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 sponsoring_contracts_download_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="sponsoring: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={() => { | ||||||
|  |                             generateSponsoringContract('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={() => { | ||||||
|  |                             generateSponsoringContract('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} | ||||||
| @@ -19,6 +19,11 @@ | |||||||
|   export let current_runners; |   export let current_runners; | ||||||
|   export let import_modal_open; |   export let import_modal_open; | ||||||
|   $: searchvalue = ""; |   $: searchvalue = ""; | ||||||
|  |   $: importButtonEnabled = | ||||||
|  |     recent_processed && | ||||||
|  |     (!(selected_org_or_team == "" || selected_org_or_team == null) || | ||||||
|  |       !(passed_org?.id == null || passed_org?.id == 0) || | ||||||
|  |       !(passed_team?.id == null || passed_team?.id == 0)); | ||||||
|   const dispatch = createEventDispatcher(); |   const dispatch = createEventDispatcher(); | ||||||
|   function cancelModal() { |   function cancelModal() { | ||||||
|     json_output = []; |     json_output = []; | ||||||
| @@ -44,7 +49,10 @@ | |||||||
|     groups = groups.concat(orgs); |     groups = groups.concat(orgs); | ||||||
|     RunnerTeamService.runnerTeamControllerGetAll().then((val) => { |     RunnerTeamService.runnerTeamControllerGetAll().then((val) => { | ||||||
|       const teams = val.map((r) => { |       const teams = val.map((r) => { | ||||||
|         return { label: `${r.parentGroup.name} > ${r.name}`, value: `TEAM_${r.id}` }; |         return { | ||||||
|  |           label: `${r.parentGroup.name} > ${r.name}`, | ||||||
|  |           value: `TEAM_${r.id}`, | ||||||
|  |         }; | ||||||
|       }); |       }); | ||||||
|       groups = groups.concat(teams); |       groups = groups.concat(teams); | ||||||
|     }); |     }); | ||||||
| @@ -120,6 +128,13 @@ | |||||||
|           .catch((err) => { |           .catch((err) => { | ||||||
|             toast.hideToast(); |             toast.hideToast(); | ||||||
|             recent_processed = true; |             recent_processed = true; | ||||||
|  |             Toastify({ | ||||||
|  |               text: $_("error-during-import"), | ||||||
|  |               duration: 500, | ||||||
|  |               backgroundColor: | ||||||
|  |                 "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", | ||||||
|  |             }).showToast(); | ||||||
|  |             cancelModal(); | ||||||
|           }); |           }); | ||||||
|       } |       } | ||||||
|       if (opened_from === "TeamDetail") { |       if (opened_from === "TeamDetail") { | ||||||
| @@ -137,6 +152,13 @@ | |||||||
|           .catch((err) => { |           .catch((err) => { | ||||||
|             toast.hideToast(); |             toast.hideToast(); | ||||||
|             recent_processed = true; |             recent_processed = true; | ||||||
|  |             Toastify({ | ||||||
|  |               text: $_("error-during-import"), | ||||||
|  |               duration: 500, | ||||||
|  |               backgroundColor: | ||||||
|  |                 "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", | ||||||
|  |             }).showToast(); | ||||||
|  |             cancelModal(); | ||||||
|           }); |           }); | ||||||
|       } |       } | ||||||
|       if (opened_from === "RunnerOverview") { |       if (opened_from === "RunnerOverview") { | ||||||
| @@ -160,6 +182,13 @@ | |||||||
|             .catch((err) => { |             .catch((err) => { | ||||||
|               toast.hideToast(); |               toast.hideToast(); | ||||||
|               recent_processed = true; |               recent_processed = true; | ||||||
|  |               Toastify({ | ||||||
|  |                 text: $_("error-during-import"), | ||||||
|  |                 duration: 500, | ||||||
|  |                 backgroundColor: | ||||||
|  |                   "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", | ||||||
|  |               }).showToast(); | ||||||
|  |               cancelModal(); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|         if (selected_org_or_team.includes("TEAM_")) { |         if (selected_org_or_team.includes("TEAM_")) { | ||||||
| @@ -182,6 +211,13 @@ | |||||||
|             .catch((err) => { |             .catch((err) => { | ||||||
|               toast.hideToast(); |               toast.hideToast(); | ||||||
|               recent_processed = true; |               recent_processed = true; | ||||||
|  |               Toastify({ | ||||||
|  |                 text: $_("error-during-import"), | ||||||
|  |                 duration: 500, | ||||||
|  |                 backgroundColor: | ||||||
|  |                   "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", | ||||||
|  |               }).showToast(); | ||||||
|  |               cancelModal(); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @@ -195,7 +231,7 @@ | |||||||
|     use:focusTrap |     use:focusTrap | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       import_modal_open = false; |       cancelModal(); | ||||||
|     }}> |     }}> | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> |       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> | ||||||
| @@ -349,6 +385,8 @@ | |||||||
|                   </table> |                   </table> | ||||||
|                 </div> |                 </div> | ||||||
|                 <button |                 <button | ||||||
|  |                   disabled={!importButtonEnabled} | ||||||
|  |                   class:opacity-50={!importButtonEnabled} | ||||||
|                   on:click={importAction} |                   on:click={importAction} | ||||||
|                   type="button" |                   type="button" | ||||||
|                   class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> |                   class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"> | ||||||
|   | |||||||
| @@ -1,398 +1,297 @@ | |||||||
| <script> | <script> | ||||||
|   import { getLocaleFromNavigator, _ } from "svelte-i18n"; |   import { getLocaleFromNavigator, _ } from "svelte-i18n"; | ||||||
|   import store from "../../store"; |   import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | ||||||
|   import { |   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|     RunnerService, |   import store from "../../store"; | ||||||
|     RunnerTeamService, |   import { | ||||||
|     RunnerOrganizationService, |     RunnerService, | ||||||
|   } from "@odit/lfk-client-js"; |     RunnerTeamService, | ||||||
|   import Toastify from "toastify-js"; |     RunnerOrganizationService, | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; |   } from "@odit/lfk-client-js"; | ||||||
|   import isEmail from "validator/es/lib/isEmail"; |   import Toastify from "toastify-js"; | ||||||
|   import Select from "svelte-select"; |   import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   let data_loaded = false; |   import isEmail from "validator/es/lib/isEmail"; | ||||||
|   export let params; |   import Select from "svelte-select"; | ||||||
|   const runner_promise = RunnerService.runnerControllerGetOne(params.runnerid); |   let data_loaded = false; | ||||||
|   $: delete_triggered = false; |   export let params; | ||||||
|   $: sponsoring_contracts_download_open = false; |   const runner_promise = RunnerService.runnerControllerGetOne(params.runnerid); | ||||||
|   $: original_data_pdf = {}; |   $: delete_triggered = false; | ||||||
|   $: original_data = {}; |   $: original_data_pdf = {}; | ||||||
|   $: editable = {}; |   $: original_data = {}; | ||||||
|   $: group = {} |   $: editable = {}; | ||||||
|   $: changes_performed = !(JSON.stringify(original_data) == JSON.stringify(editable)); |   $: group = {}; | ||||||
|   $: isEmailValid = |   $: changes_performed = !( | ||||||
|     (editable.email || "") === "" || |     JSON.stringify(original_data) == JSON.stringify(editable) | ||||||
|     (editable.email && isEmail(editable.email || "")); |   ); | ||||||
|   $: isFirstnameValid = editable.firstname !== ""; |   $: isEmailValid = | ||||||
|   $: isLastnameValid = editable.lastname !== ""; |     (editable.email || "") === "" || | ||||||
|   $: save_enabled = |     (editable.email && isEmail(editable.email || "")); | ||||||
|     changes_performed && |   $: isFirstnameValid = editable.firstname !== ""; | ||||||
|     isFirstnameValid && |   $: isLastnameValid = editable.lastname !== ""; | ||||||
|     isLastnameValid && |   $: save_enabled = | ||||||
|     isEmailValid && |     changes_performed && | ||||||
|     editable.group != null; |     isFirstnameValid && | ||||||
|   runner_promise.then((data) => { |     isLastnameValid && | ||||||
|     data_loaded = true; |     isEmailValid && | ||||||
|     original_data_pdf = Object.assign(original_data_pdf, data); |     editable.group != null; | ||||||
|     data.group = data.group.id; |   $: sponsoring_contracts_show = true; | ||||||
|     original_data = Object.assign(original_data, data); |   $: cards_show = true; | ||||||
|     editable = Object.assign(editable, original_data); |   $: generate_runners = [original_data_pdf]; | ||||||
|  |   runner_promise.then((data) => { | ||||||
|     RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => { |     data_loaded = true; | ||||||
|       const orgs = val.map((r) => { |     original_data_pdf = Object.assign(original_data_pdf, data); | ||||||
|         return { label: r.name, value: r }; |     data.group = data.group.id; | ||||||
|       }); |     original_data = Object.assign(original_data, data); | ||||||
|       groups = groups.concat(orgs); |     editable = Object.assign(editable, original_data); | ||||||
|       RunnerTeamService.runnerTeamControllerGetAll().then((val) => { |  | ||||||
|         const teams = val.map((r) => { |     RunnerOrganizationService.runnerOrganizationControllerGetAll().then( | ||||||
|           return { label: `${r.parentGroup.name} > ${r.name}`, value: r }; |       (val) => { | ||||||
|         }); |         const orgs = val.map((r) => { | ||||||
|         groups = groups.concat(teams); |           return { label: r.name, value: r }; | ||||||
|         group = groups.find(g => g.value.id == editable.group) |         }); | ||||||
|       }); |         groups = groups.concat(orgs); | ||||||
|     }); |         RunnerTeamService.runnerTeamControllerGetAll().then((val) => { | ||||||
|   }); |           const teams = val.map((r) => { | ||||||
|   document.addEventListener("click", function (e) { |             return { label: `${r.parentGroup.name} > ${r.name}`, value: r }; | ||||||
|     if ( |           }); | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown" && |           groups = groups.concat(teams); | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown:menu" |           group = groups.find((g) => g.value.id == editable.group); | ||||||
|     ) { |         }); | ||||||
|       sponsoring_contracts_download_open = false; |       } | ||||||
|     } |     ); | ||||||
|   }); |   }); | ||||||
|   let groups = []; |   let groups = []; | ||||||
|   function submit() { |   function submit() { | ||||||
|     if (data_loaded === true && save_enabled) { |     if (data_loaded === true && save_enabled) { | ||||||
|       Toastify({ |       Toastify({ | ||||||
|         text: $_("updating-runner"), |         text: $_("updating-runner"), | ||||||
|         duration: 2500, |         duration: 2500, | ||||||
|       }).showToast(); |       }).showToast(); | ||||||
|       let postdata = {}; |       let postdata = {}; | ||||||
|       postdata = Object.assign(postdata, editable); |       postdata = Object.assign(postdata, editable); | ||||||
|       RunnerService.runnerControllerPut(original_data.id, postdata) |       RunnerService.runnerControllerPut(original_data.id, postdata) | ||||||
|         .then((resp) => { |         .then((resp) => { | ||||||
|           Object.assign(original_data, editable); |           Object.assign(original_data, editable); | ||||||
|           original_data = original_data; |           original_data = original_data; | ||||||
|           Toastify({ |           Toastify({ | ||||||
|             text: $_("runner-updated"), |             text: $_("runner-updated"), | ||||||
|             duration: 2500, |             duration: 2500, | ||||||
|             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|           }).showToast(); |           }).showToast(); | ||||||
|         }) |         }) | ||||||
|         .catch((err) => {}); |         .catch((err) => {}); | ||||||
|     } else { |     } else { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   function deleteRunner() { |   function deleteRunner() { | ||||||
|     RunnerService.runnerControllerRemove(original_data.id, true) |     RunnerService.runnerControllerRemove(original_data.id, true) | ||||||
|       .then((resp) => { |       .then((resp) => { | ||||||
|         location.replace("./"); |         location.replace("./"); | ||||||
|       }) |       }) | ||||||
|       .catch((err) => {}); |       .catch((err) => {}); | ||||||
|   } |   } | ||||||
|   function generateSponsoringContract(locale) { | </script> | ||||||
|     sponsoring_contracts_download_open = false; |  | ||||||
|     const toast = Toastify({ | {#await runner_promise} | ||||||
|       text: $_("generating-pdf"), |   {$_('loading-runners')} | ||||||
|       duration: -1, | {:then} | ||||||
|     }).showToast(); |   <section class="container p-5 select-none"> | ||||||
|     fetch( |     <div class="flex flex-row mb-4"> | ||||||
|       `https://dev.lauf-fuer-kaya.de/documents/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, |       <div class="w-full"> | ||||||
|       { |         <nav class="w-full flex"> | ||||||
|         method: "POST", |           <ol class="list-none flex flex-row items-center justify-start"> | ||||||
|         headers: { |             <li class="flex items-center"> | ||||||
|           "Content-Type": "application/json", |               <svg | ||||||
|         }, |                 xmlns="http://www.w3.org/2000/svg" | ||||||
|         body: JSON.stringify([original_data_pdf]), |                 viewBox="0 0 24 24" | ||||||
|       } |                 class="flex-shrink-0 w-5 h-5 mr-2" | ||||||
|     ) |                 fill="currentColor" | ||||||
|       .then((response) => { |                 width="24" | ||||||
|         if (response.status != "200") { |                 height="24"><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|           toast.hideToast(); |                 <path | ||||||
|           Toastify({ |                   d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z" /></svg> | ||||||
|             text: $_("pdf-generation-failed"), |             </li> | ||||||
|             duration: 3500, |             <li class="flex items-center"> | ||||||
|             backgroundColor: |               <a class="mr-2" href="./">{$_('runners')}</a><svg | ||||||
|               "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", |                 stroke="currentColor" | ||||||
|           }).showToast(); |                 fill="none" | ||||||
|         } else { |                 stroke-width="2" | ||||||
|           return response.blob(); |                 viewBox="0 0 24 24" | ||||||
|         } |                 stroke-linecap="round" | ||||||
|       }) |                 stroke-linejoin="round" | ||||||
|       .then((blob) => { |                 class="h-3 w-3 mr-2 stroke-current" | ||||||
|         const url = window.URL.createObjectURL(blob); |                 height="1em" | ||||||
|         let a = document.createElement("a"); |                 width="1em" | ||||||
|         a.href = url; |                 xmlns="http://www.w3.org/2000/svg"><line | ||||||
|         a.download = |                   x1="5" | ||||||
|           "Sponsoring_" + |                   y1="12" | ||||||
|           original_data.firstname + |                   x2="19" | ||||||
|           (original_data.middlename || "") + |                   y2="12" /> | ||||||
|           original_data.lastname + |                 <polyline points="12 5 19 12 12 19" /></svg> | ||||||
|           ".pdf"; |             </li> | ||||||
|         document.body.appendChild(a); |             <li class="flex items-center"> | ||||||
|         a.click(); |               <span class="mr-2">{original_data.firstname} | ||||||
|         a.remove(); |                 {original_data.middlename || ''} | ||||||
|         toast.hideToast(); |                 {original_data.lastname}</span> | ||||||
|         Toastify({ |             </li> | ||||||
|           text: $_("pdf-successfully-generated"), |           </ol> | ||||||
|           duration: 3500, |         </nav> | ||||||
|           backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", |       </div> | ||||||
|         }).showToast(); |     </div> | ||||||
|       }) |     <div class="mb-8 text-3xl font-extrabold leading-tight"> | ||||||
|       .catch((err) => { |       {original_data.firstname} | ||||||
|         console.error(err); |       {original_data.middlename || ''} | ||||||
|       }); |       {original_data.lastname} | ||||||
|   } |       <span data-id="runner_actions_${editable.id}"> | ||||||
| </script> |         {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:DELETE')} | ||||||
|  |           {#if delete_triggered} | ||||||
| {#await runner_promise} |             <button | ||||||
|   {$_('loading-runners')} |               on:click={deleteRunner} | ||||||
| {:then} |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('confirm-deletion')}</button> | ||||||
|   <section class="container p-5 select-none"> |             <button | ||||||
|     <div class="flex flex-row mb-4"> |               on:click={() => { | ||||||
|       <div class="w-full"> |                 delete_triggered = !delete_triggered; | ||||||
|         <nav class="w-full flex"> |               }} | ||||||
|           <ol class="list-none flex flex-row items-center justify-start"> |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm">{$_('cancel')}</button> | ||||||
|             <li class="flex items-center"> |           {/if} | ||||||
|               <svg |           <GenerateSponsoringContracts | ||||||
|                 xmlns="http://www.w3.org/2000/svg" |             bind:sponsoring_contracts_show | ||||||
|                 viewBox="0 0 24 24" |             bind:generate_runners /> | ||||||
|                 class="flex-shrink-0 w-5 h-5 mr-2" |           <GenerateRunnerCards | ||||||
|                 fill="currentColor" |             bind:sponsoring_contracts_show | ||||||
|                 width="24" |             bind:generate_runners /> | ||||||
|                 height="24"><path fill="none" d="M0 0h24v24H0z" /> |           {#if !delete_triggered} | ||||||
|                 <path |             <button | ||||||
|                   d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z" /></svg> |               on:click={() => { | ||||||
|             </li> |                 delete_triggered = true; | ||||||
|             <li class="flex items-center"> |               }} | ||||||
|               <a class="mr-2" href="./">{$_('runners')}</a><svg |               type="button" | ||||||
|                 stroke="currentColor" |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('delete-runner')}</button> | ||||||
|                 fill="none" |           {/if} | ||||||
|                 stroke-width="2" |         {/if} | ||||||
|                 viewBox="0 0 24 24" |         {#if !delete_triggered} | ||||||
|                 stroke-linecap="round" |           <button | ||||||
|                 stroke-linejoin="round" |             disabled={!save_enabled} | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" |             class:opacity-50={!save_enabled} | ||||||
|                 height="1em" |             type="button" | ||||||
|                 width="1em" |             on:click={submit} | ||||||
|                 xmlns="http://www.w3.org/2000/svg"><line |             class="w-full 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> | ||||||
|                   x1="5" |         {/if} | ||||||
|                   y1="12" |       </span> | ||||||
|                   x2="19" |     </div> | ||||||
|                   y2="12" /> |     <!--  --> | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg> |     <div class="text-sm w-full"> | ||||||
|             </li> |       <label | ||||||
|             <li class="flex items-center"> |         for="firstname" | ||||||
|               <span class="mr-2">{original_data.firstname} |         class="font-medium text-gray-700">{$_('first-name')}</label> | ||||||
|                 {original_data.middlename || ''} |       <input | ||||||
|                 {original_data.lastname}</span> |         autocomplete="off" | ||||||
|             </li> |         placeholder={$_('first-name')} | ||||||
|           </ol> |         type="text" | ||||||
|         </nav> |         class:border-red-500={!isFirstnameValid} | ||||||
|       </div> |         class:focus:border-red-500={!isFirstnameValid} | ||||||
|     </div> |         class:focus:ring-red-500={!isFirstnameValid} | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> |         bind:value={editable.firstname} | ||||||
|       {original_data.firstname} |         name="firstname" | ||||||
|       {original_data.middlename || ''} |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> | ||||||
|       {original_data.lastname} |       {#if !isFirstnameValid} | ||||||
|       <span data-id="runner_actions_${editable.id}"> |         <span | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:DELETE')} |           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> | ||||||
|           {#if delete_triggered} |           {$_('first-name-is-required')} | ||||||
|             <button |         </span> | ||||||
|               on:click={deleteRunner} |       {/if} | ||||||
|               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('confirm-deletion')}</button> |     </div> | ||||||
|             <button |     <div class="text-sm w-full"> | ||||||
|               on:click={() => { |       <label | ||||||
|                 delete_triggered = !delete_triggered; |         for="middlename" | ||||||
|               }} |         class="font-medium text-gray-700">{$_('middle-name')}</label> | ||||||
|               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm">{$_('cancel')}</button> |       <input | ||||||
|           {/if} |         autocomplete="off" | ||||||
|           <div id="sponsoring:dropdown" class="relative inline-block"> |         placeholder={$_('middle-name')} | ||||||
|             <div> |         type="text" | ||||||
|               <button |         bind:value={editable.middlename} | ||||||
|                 on:click={() => { |         name="middlename" | ||||||
|                   sponsoring_contracts_download_open = !sponsoring_contracts_download_open; |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> | ||||||
|                 }} |     </div> | ||||||
|                 type="button" |     <div class="text-sm w-full"> | ||||||
|                 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" |       <label | ||||||
|                 id="options-menu" |         for="lastname" | ||||||
|                 aria-haspopup="true" |         class="font-medium text-gray-700">{$_('last-name')}</label> | ||||||
|                 aria-expanded="true"> |       <input | ||||||
|                 {$_('generate-sponsoring-contract')} |         autocomplete="off" | ||||||
|                 <svg |         placeholder={$_('last-name')} | ||||||
|                   xmlns="http://www.w3.org/2000/svg" |         type="text" | ||||||
|                   width="24" |         bind:value={editable.lastname} | ||||||
|                   height="24" |         class:border-red-500={!isLastnameValid} | ||||||
|                   viewBox="0 0 24 24" |         class:focus:border-red-500={!isLastnameValid} | ||||||
|                   class="-mr-1 ml-2 h-5 w-5"><path |         class:focus:ring-red-500={!isLastnameValid} | ||||||
|                     fill="none" |         name="lastname" | ||||||
|                     d="M0 0h24v24H0z" /> |         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" /> | ||||||
|                   <path |       {#if !isLastnameValid} | ||||||
|                     fill="currentColor" |         <span | ||||||
|                     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> |           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> | ||||||
|               </button> |           {$_('last-name-is-required')} | ||||||
|             </div> |         </span> | ||||||
|             {#if sponsoring_contracts_download_open} |       {/if} | ||||||
|               <div |     </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" |     <div class="text-sm w-full"> | ||||||
|                 id="sponsoring:dropdown:menu"> |       <label | ||||||
|                 <div |         for="email" | ||||||
|                   class="py-1" |         class="font-medium text-gray-700">{$_('e-mail-adress')}</label> | ||||||
|                   role="menu" |       <input | ||||||
|                   aria-orientation="vertical" |         autocomplete="off" | ||||||
|                   aria-labelledby="options-menu"> |         placeholder={$_('e-mail-adress')} | ||||||
|                   <span |         type="email" | ||||||
|                     class="block w-full text-left px-4 py-2 text-sm text-gray-700">{$_('select-language')}</span> |         bind:value={editable.email} | ||||||
|                   <button |         class:border-red-500={!isEmailValid} | ||||||
|                     on:click={() => { |         class:focus:border-red-500={!isEmailValid} | ||||||
|                       generateSponsoringContract('de'); |         class:focus:ring-red-500={!isEmailValid} | ||||||
|                     }} |         name="email" | ||||||
|                     type="submit" |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> | ||||||
|                     class="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 inline-flex" |       {#if !isEmailValid} | ||||||
|                     role="menuitem"> |         <span | ||||||
|                     {$_('german')} |           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> | ||||||
|                   </button> |           {$_('valid-email-is-required')} | ||||||
|                   <button |         </span> | ||||||
|                     on:click={() => { |       {/if} | ||||||
|                       generateSponsoringContract('en'); |     </div> | ||||||
|                     }} |     <div class="text-sm w-full"> | ||||||
|                     type="submit" |       <label for="phone" class="font-medium text-gray-700">{$_('phone')}</label> | ||||||
|                     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 inline-flex" |       <input | ||||||
|                     role="menuitem"> |         autocomplete="off" | ||||||
|                     {$_('english')} |         placeholder={$_('phone')} | ||||||
|                   </button> |         type="tel" | ||||||
|                 </div> |         bind:value={editable.phone} | ||||||
|               </div> |         name="phone" | ||||||
|             {/if} |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> | ||||||
|           </div> |     </div> | ||||||
|           {#if !delete_triggered} |     <div class="text-sm w-full"> | ||||||
|             <button |       <span class="font-medium text-gray-700">{$_('group')}</span> | ||||||
|               on:click={() => { |       <Select | ||||||
|                 delete_triggered = true; |         containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | ||||||
|               }} |         itemFilter={(label, filterText, option) => label | ||||||
|               type="button" |             .toLowerCase() | ||||||
|               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('delete-runner')}</button> |             .includes( | ||||||
|           {/if} |               filterText.toLowerCase() | ||||||
|         {/if} |             ) || option.id.value | ||||||
|         {#if !delete_triggered} |             .toString() | ||||||
|           <button |             .startsWith(filterText.toLowerCase())} | ||||||
|             disabled={!save_enabled} |         items={groups} | ||||||
|             class:opacity-50={!save_enabled} |         showChevron={true} | ||||||
|             type="button" |         placeholder={$_('search-for-an-organization-or-team-by-name-or-id')} | ||||||
|             on:click={submit} |         noOptionsMessage={$_('no-organization-or-team-found')} | ||||||
|             class="w-full 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> |         bind:selectedValue={group} | ||||||
|         {/if} |         on:select={(selectedValue) => { | ||||||
|       </span> |           editable.group = selectedValue.detail.value.id; | ||||||
|     </div> |         }} | ||||||
|     <!--  --> |         on:clear={() => (editable.group = null)} /> | ||||||
|     <div class="text-sm w-full"> |     </div> | ||||||
|       <label |     <div class="text-sm w-full"> | ||||||
|         for="firstname" |       <span class="font-medium text-gray-700">{$_('distance')}</span> | ||||||
|         class="font-medium text-gray-700">{$_('first-name')}</label> |       <br /> | ||||||
|       <input |       <span class="text-gray-700">{original_data.distance} km</span> | ||||||
|         autocomplete="off" |     </div> | ||||||
|         placeholder={$_('first-name')} |   </section> | ||||||
|         type="text" | {:catch error} | ||||||
|         class:border-red-500={!isFirstnameValid} |   <PromiseError {error} /> | ||||||
|         class:focus:border-red-500={!isFirstnameValid} | {/await} | ||||||
|         class:focus:ring-red-500={!isFirstnameValid} |  | ||||||
|         bind:value={editable.firstname} |  | ||||||
|         name="firstname" |  | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> |  | ||||||
|       {#if !isFirstnameValid} |  | ||||||
|         <span |  | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> |  | ||||||
|           {$_('first-name-is-required')} |  | ||||||
|         </span> |  | ||||||
|       {/if} |  | ||||||
|     </div> |  | ||||||
|     <div class="text-sm w-full"> |  | ||||||
|       <label |  | ||||||
|         for="middlename" |  | ||||||
|         class="font-medium text-gray-700">{$_('middle-name')}</label> |  | ||||||
|       <input |  | ||||||
|         autocomplete="off" |  | ||||||
|         placeholder={$_('middle-name')} |  | ||||||
|         type="text" |  | ||||||
|         bind:value={editable.middlename} |  | ||||||
|         name="middlename" |  | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> |  | ||||||
|     </div> |  | ||||||
|     <div class="text-sm w-full"> |  | ||||||
|       <label |  | ||||||
|         for="lastname" |  | ||||||
|         class="font-medium text-gray-700">{$_('last-name')}</label> |  | ||||||
|       <input |  | ||||||
|         autocomplete="off" |  | ||||||
|         placeholder={$_('last-name')} |  | ||||||
|         type="text" |  | ||||||
|         bind:value={editable.lastname} |  | ||||||
|         class:border-red-500={!isLastnameValid} |  | ||||||
|         class:focus:border-red-500={!isLastnameValid} |  | ||||||
|         class:focus:ring-red-500={!isLastnameValid} |  | ||||||
|         name="lastname" |  | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> |  | ||||||
|       {#if !isLastnameValid} |  | ||||||
|         <span |  | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> |  | ||||||
|           {$_('last-name-is-required')} |  | ||||||
|         </span> |  | ||||||
|       {/if} |  | ||||||
|     </div> |  | ||||||
|     <div class="text-sm w-full"> |  | ||||||
|       <label |  | ||||||
|         for="email" |  | ||||||
|         class="font-medium text-gray-700">{$_('e-mail-adress')}</label> |  | ||||||
|       <input |  | ||||||
|         autocomplete="off" |  | ||||||
|         placeholder={$_('e-mail-adress')} |  | ||||||
|         type="email" |  | ||||||
|         bind:value={editable.email} |  | ||||||
|         class:border-red-500={!isEmailValid} |  | ||||||
|         class:focus:border-red-500={!isEmailValid} |  | ||||||
|         class:focus:ring-red-500={!isEmailValid} |  | ||||||
|         name="email" |  | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> |  | ||||||
|       {#if !isEmailValid} |  | ||||||
|         <span |  | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> |  | ||||||
|           {$_('valid-email-is-required')} |  | ||||||
|         </span> |  | ||||||
|       {/if} |  | ||||||
|     </div> |  | ||||||
|     <div class="text-sm w-full"> |  | ||||||
|       <label for="phone" class="font-medium text-gray-700">{$_('phone')}</label> |  | ||||||
|       <input |  | ||||||
|         autocomplete="off" |  | ||||||
|         placeholder={$_('phone')} |  | ||||||
|         type="tel" |  | ||||||
|         bind:value={editable.phone} |  | ||||||
|         name="phone" |  | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> |  | ||||||
|     </div> |  | ||||||
|     <div class="text-sm w-full"> |  | ||||||
|       <span class="font-medium text-gray-700">{$_('group')}</span> |  | ||||||
|       <Select |  | ||||||
|         containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |  | ||||||
|         itemFilter={(label, filterText, option) => label |  | ||||||
|             .toLowerCase() |  | ||||||
|             .includes( |  | ||||||
|               filterText.toLowerCase() |  | ||||||
|             ) || option.id.value.toString().startsWith(filterText.toLowerCase())} |  | ||||||
|         items={groups} |  | ||||||
|         showChevron={true} |  | ||||||
|         placeholder={$_('search-for-an-organization-or-team-by-name-or-id')} |  | ||||||
|         noOptionsMessage={$_('no-organization-or-team-found')} |  | ||||||
|         bind:selectedValue={group} |  | ||||||
|         on:select={(selectedValue) => {editable.group = selectedValue.detail.value.id}} |  | ||||||
|         on:clear={() => (editable.group = null)} /> |  | ||||||
|     </div> |  | ||||||
|     <div class="text-sm w-full"> |  | ||||||
|       <span class="font-medium text-gray-700">{$_('distance')}</span> |  | ||||||
|       <br /> |  | ||||||
|       <span class="text-gray-700">{original_data.distance} km</span> |  | ||||||
|     </div> |  | ||||||
|   </section> |  | ||||||
| {:catch error} |  | ||||||
|   <PromiseError {error} /> |  | ||||||
| {/await} |  | ||||||
|   | |||||||
| @@ -1,364 +1,256 @@ | |||||||
| <script> | <script> | ||||||
|   import { getLocaleFromNavigator, _ } from "svelte-i18n"; |   import { getLocaleFromNavigator, _ } from "svelte-i18n"; | ||||||
|   import { |   import { | ||||||
|     RunnerService, |     RunnerService, | ||||||
|     RunnerTeamService, |     RunnerTeamService, | ||||||
|     RunnerOrganizationService, |     RunnerOrganizationService, | ||||||
|   } from "@odit/lfk-client-js"; |   } from "@odit/lfk-client-js"; | ||||||
|   import store from "../../store"; |   import store from "../../store"; | ||||||
|   import RunnersEmptyState from "./RunnersEmptyState.svelte"; |   import RunnersEmptyState from "./RunnersEmptyState.svelte"; | ||||||
|   import Select from "svelte-select"; |   import Select from "svelte-select"; | ||||||
|   import Toastify from "toastify-js"; |   import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | ||||||
|   $: searchvalue = ""; |   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|   $: active_deletes = []; |   $: searchvalue = ""; | ||||||
|   export let current_runners = []; |   $: active_deletes = []; | ||||||
|   const runners_promise = RunnerService.runnerControllerGetAll().then((val) => { |   export let current_runners = []; | ||||||
|     current_runners = val; |   const runners_promise = RunnerService.runnerControllerGetAll().then((val) => { | ||||||
|   }); |     current_runners = val; | ||||||
|   $: selectedFilter_teams = null; |   }); | ||||||
|   $: selectedFilter = null; |   $: selectedFilter_teams = null; | ||||||
|   $: filter__teams = selectedFilter_teams || []; |   $: selectedFilter = null; | ||||||
|   $: filter__orgs = selectedFilter || []; |   $: filter__teams = selectedFilter_teams || []; | ||||||
|   $: filterGroupIDs = filter__teams.concat(filter__orgs).map((i) => i.value); |   $: filter__orgs = selectedFilter || []; | ||||||
|   $: sponsoring_contracts_download_open = false; |   $: filterGroupIDs = filter__teams.concat(filter__orgs).map((i) => i.value); | ||||||
|   $: teams = []; |   $: sponsoring_contracts_show = current_runners.some( | ||||||
|   $: orgs = []; |     (r) => r.is_selected === true | ||||||
|   $: mappedteams = teams.map(function (g) { |   ); | ||||||
|     return { value: g.id, label: g.parentGroup.name + " > " + g.name }; |   $: cards_show = current_runners.some( | ||||||
|   }); |     (r) => r.is_selected === true | ||||||
|   $: selectgroups = orgs |   ); | ||||||
|     .map(function (g) { |   $: generate_runners = current_runners.filter((r) => r.is_selected === true); | ||||||
|       return { value: g.id, label: g.name }; |   $: teams = []; | ||||||
|     }) |   $: orgs = []; | ||||||
|     .concat(mappedteams); |   $: mappedteams = teams.map(function (g) { | ||||||
|   document.addEventListener("click", function (e) { |     return { value: g.id, label: g.parentGroup.name + " > " + g.name }; | ||||||
|     if ( |   }); | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown" && |   $: selectgroups = orgs | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown:menu" |     .map(function (g) { | ||||||
|     ) { |       return { value: g.id, label: g.name }; | ||||||
|       sponsoring_contracts_download_open = false; |     }) | ||||||
|     } |     .concat(mappedteams); | ||||||
|   }); |  | ||||||
|   RunnerTeamService.runnerTeamControllerGetAll().then((val) => { |   RunnerTeamService.runnerTeamControllerGetAll().then((val) => { | ||||||
|     teams = val; |     teams = val; | ||||||
|   }); |   }); | ||||||
|   RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => { |   RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => { | ||||||
|     orgs = val; |     orgs = val; | ||||||
|   }); |   }); | ||||||
|   function should_display_based_on_id(id) { |   function should_display_based_on_id(id) { | ||||||
|     if (searchvalue.toString().slice(-1) === "*") { |     if (searchvalue.toString().slice(-1) === "*") { | ||||||
|       return id.toString().startsWith(searchvalue.replace("*", "")); |       return id.toString().startsWith(searchvalue.replace("*", "")); | ||||||
|     } |     } | ||||||
|     return id.toString() === searchvalue; |     return id.toString() === searchvalue; | ||||||
|   } |   } | ||||||
|   function generateSponsoringContract(locale) { | </script> | ||||||
|     sponsoring_contracts_download_open = false; |  | ||||||
|     const toast = Toastify({ | {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:GET')} | ||||||
|       text: $_("generating-pdf"), |   {#await runners_promise} | ||||||
|       duration: -1, |     <div | ||||||
|     }).showToast(); |       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|     fetch( |       role="alert"> | ||||||
|       `https://dev.lauf-fuer-kaya.de/documents/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, |       <p class="font-bold">{$_('runners-are-being-loaded')}</p> | ||||||
|       { |       <p class="text-sm">{$_('this-might-take-a-moment')}</p> | ||||||
|         method: "POST", |     </div> | ||||||
|         headers: { |   {:then} | ||||||
|           "Content-Type": "application/json", |     {#if current_runners.length === 0} | ||||||
|         }, |       <RunnersEmptyState /> | ||||||
|         body: JSON.stringify( |     {:else} | ||||||
|           current_runners.filter((r) => r.is_selected === true) |       <input | ||||||
|         ), |         type="search" | ||||||
|       } |         bind:value={searchvalue} | ||||||
|     ) |         placeholder={$_('datatable.search')} | ||||||
|       .then((response) => { |         aria-label={$_('datatable.search')} | ||||||
|         if (response.status != "200") { |         class="gridjs-input gridjs-search-input mb-4" /> | ||||||
|           toast.hideToast(); |       <div class="block mb-6"> | ||||||
|           Toastify({ |         <label | ||||||
|             text: $_("pdf-generation-failed"), |           for="country" | ||||||
|             duration: 3500, |           class="text-sm font-medium text-gray-700">{$_('filter-by-organization-team')}</label> | ||||||
|             backgroundColor: |         <Select | ||||||
|               "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", |           on:select={(event) => { | ||||||
|           }).showToast(); |             selectedFilter = event.detail; | ||||||
|         } else { |           }} | ||||||
|           return response.blob(); |           selectedValue={selectedFilter} | ||||||
|         } |           placeholder={$_('filter-by-organization-team')} | ||||||
|       }) |           containerClasses="mt-1 py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" | ||||||
|       .then((blob) => { |           items={selectgroups} | ||||||
|         const url = window.URL.createObjectURL(blob); |           isMulti={true} /> | ||||||
|         let a = document.createElement("a"); |       </div> | ||||||
|         a.href = url; |       <div class="h-12"> | ||||||
|         a.download = "Sponsoring.pdf"; |         <GenerateSponsoringContracts | ||||||
|         document.body.appendChild(a); |           bind:sponsoring_contracts_show | ||||||
|         a.click(); |           bind:generate_runners /> | ||||||
|         a.remove(); |         <GenerateRunnerCards | ||||||
|         toast.hideToast(); |           bind:cards_show | ||||||
|         Toastify({ |           bind:generate_runners /> | ||||||
|           text: $_("pdf-successfully-generated"), |       </div> | ||||||
|           duration: 3500, |       <div | ||||||
|           backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", |         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> | ||||||
|         }).showToast(); |         <table class="divide-y divide-gray-200 w-full"> | ||||||
|       }) |           <thead class="bg-gray-50"> | ||||||
|       .catch((err) => { |             <tr> | ||||||
|         console.error(err); |               <th | ||||||
|       }); |                 scope="col" | ||||||
|   } |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
| </script> |                 <span | ||||||
|  |                   on:click={() => { | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:GET')} |                     const newstate = !current_runners.some((r) => r.is_selected === true); | ||||||
|   {#await runners_promise} |                     current_runners = current_runners.map((r) => { | ||||||
|     <div |                       r.is_selected = newstate; | ||||||
|       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" |                       return r; | ||||||
|       role="alert"> |                     }); | ||||||
|       <p class="font-bold">{$_('runners-are-being-loaded')}</p> |                   }} | ||||||
|       <p class="text-sm">{$_('this-might-take-a-moment')}</p> |                   class="underline cursor-pointer select-none">{#if current_runners.some((r) => r.is_selected === true)} | ||||||
|     </div> |                     {$_('deselect-all')} | ||||||
|   {:then} |                   {:else}{$_('select-all')}{/if} | ||||||
|     {#if current_runners.length === 0} |                 </span> | ||||||
|       <RunnersEmptyState /> |               </th> | ||||||
|     {:else} |               <th | ||||||
|       <input |                 scope="col" | ||||||
|         type="search" |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|         bind:value={searchvalue} |                 {$_('name')} | ||||||
|         placeholder={$_('datatable.search')} |               </th> | ||||||
|         aria-label={$_('datatable.search')} |               <th | ||||||
|         class="gridjs-input gridjs-search-input mb-4" /> |                 scope="col" | ||||||
|       <div class="block mb-6"> |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|         <label |                 {$_('contact-information')} | ||||||
|           for="country" |               </th> | ||||||
|           class="text-sm font-medium text-gray-700">{$_('filter-by-organization-team')}</label> |               <th | ||||||
|         <Select |                 scope="col" | ||||||
|           on:select={(event) => { |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|             selectedFilter = event.detail; |                 {$_('group')} | ||||||
|           }} |               </th> | ||||||
|           selectedValue={selectedFilter} |               <th | ||||||
|           placeholder={$_('filter-by-organization-team')} |                 scope="col" | ||||||
|           containerClasses="mt-1 py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|           items={selectgroups} |                 {$_('distance-in-km')} | ||||||
|           isMulti={true} /> |               </th> | ||||||
|       </div> |               <th scope="col" class="relative px-6 py-3"> | ||||||
|       <div class="h-12"> |                 <span class="sr-only">{$_('action')}</span> | ||||||
|         {#if current_runners.some((r) => r.is_selected === true)} |               </th> | ||||||
|           <div id="sponsoring:dropdown" class="relative inline-block"> |             </tr> | ||||||
|             <div> |           </thead> | ||||||
|               <button |           <tbody class="divide-y divide-gray-200"> | ||||||
|                 on:click={() => { |             {#each current_runners as runner} | ||||||
|                   sponsoring_contracts_download_open = !sponsoring_contracts_download_open; |               {#if runner.firstname | ||||||
|                 }} |                 .toLowerCase() | ||||||
|                 type="button" |                 .includes( | ||||||
|                 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" |                   searchvalue.toLowerCase() | ||||||
|                 id="options-menu" |                 ) || runner.lastname | ||||||
|                 aria-haspopup="true" |                   .toLowerCase() | ||||||
|                 aria-expanded="true"> |                   .includes( | ||||||
|                 {$_('generate-sponsoring-contracts')} |                     searchvalue.toLowerCase() | ||||||
|                 <svg |                   ) || should_display_based_on_id(runner.id)} | ||||||
|                   xmlns="http://www.w3.org/2000/svg" |                 {#if filterGroupIDs.includes(runner.group.id) || filterGroupIDs.includes(runner.group.parentGroup?.id) || filterGroupIDs.length === 0} | ||||||
|                   width="24" |                   <tr | ||||||
|                   height="24" |                     data-rowid="user_{runner.id}" | ||||||
|                   viewBox="0 0 24 24" |                     data-groupid={runner.group.id}> | ||||||
|                   class="-mr-1 ml-2 h-5 w-5"><path |                     <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                     fill="none" |                       <input | ||||||
|                     d="M0 0h24v24H0z" /> |                         bind:checked={runner.is_selected} | ||||||
|                   <path |                         type="checkbox" | ||||||
|                     fill="currentColor" |                         class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" /> | ||||||
|                     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> |                     </td> | ||||||
|               </button> |                     <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|             </div> |                       <div class="flex items-center"> | ||||||
|             {#if sponsoring_contracts_download_open} |                         <div class="ml-4"> | ||||||
|               <div |                           <div class="text-sm font-medium text-gray-900"> | ||||||
|                 class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5" |                             {runner.firstname} | ||||||
|                 id="sponsoring:dropdown:menu"> |                             {runner.middlename || ''} | ||||||
|                 <div |                             {runner.lastname} | ||||||
|                   class="py-1" |                           </div> | ||||||
|                   role="menu" |                         </div> | ||||||
|                   aria-orientation="vertical" |                       </div> | ||||||
|                   aria-labelledby="options-menu"> |                     </td> | ||||||
|                   <span |                     <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                     class="block w-full text-left px-4 py-2 text-sm text-gray-700">{$_('select-language')}</span> |                       {#if runner.email} | ||||||
|                   <button |                         <div class="text-sm text-gray-500">{runner.email}</div> | ||||||
|                     on:click={() => { |                       {/if} | ||||||
|                       generateSponsoringContract('de'); |                       {#if runner.phone} | ||||||
|                     }} |                         <div class="text-sm text-gray-500">{runner.phone}</div> | ||||||
|                     type="submit" |                       {/if} | ||||||
|                     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 inline-flex" |                       {#if runner.address.address1 !== null} | ||||||
|                     role="menuitem"> |                         {runner.address.address1}<br /> | ||||||
|                     {$_('german')} |                         {runner.address.address2 || ''}<br /> | ||||||
|                   </button> |                         {runner.address.postalcode} | ||||||
|                   <button |                         {runner.address.city} | ||||||
|                     on:click={() => { |                         {runner.address.country} | ||||||
|                       generateSponsoringContract('en'); |                       {/if} | ||||||
|                     }} |                     </td> | ||||||
|                     type="submit" |                     <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                     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 inline-flex" |                       {#if runner.group.responseType === 'RUNNERTEAM'} | ||||||
|                     role="menuitem"> |                         <a | ||||||
|                     {$_('english')} |                           href="../teams/{runner.group.id}" | ||||||
|                   </button> |                           class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{runner.group.name}</a> | ||||||
|                 </div> |                       {/if} | ||||||
|               </div> |                       {#if runner.group.responseType === 'RUNNERORGANIZATION'} | ||||||
|             {/if} |                         <a | ||||||
|           </div> |                           href="../orgs/{runner.group.id}" | ||||||
|         {/if} |                           class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{runner.group.name}</a> | ||||||
|       </div> |                       {/if} | ||||||
|       <div |                     </td> | ||||||
|         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> |                     <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|         <table class="divide-y divide-gray-200 w-full"> |                       {runner.distance} | ||||||
|           <thead class="bg-gray-50"> |                     </td> | ||||||
|             <tr> |                     {#if active_deletes[runner.id] === true} | ||||||
|               <th |                       <td | ||||||
|                 scope="col" |                         class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |                         <button | ||||||
|                 <span |                           on:click={() => { | ||||||
|                   on:click={() => { |                             active_deletes[runner.id] = false; | ||||||
|                     const newstate = !current_runners.some((r) => r.is_selected === true); |                           }} | ||||||
|                     current_runners = current_runners.map((r) => { |                           tabindex="0" | ||||||
|                       r.is_selected = newstate; |                           class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button> | ||||||
|                       return r; |                         <button | ||||||
|                     }); |                           on:click={() => { | ||||||
|                   }} |                             RunnerService.runnerControllerRemove(runner.id, true) | ||||||
|                   class="underline cursor-pointer select-none">{#if current_runners.some((r) => r.is_selected === true)} |                               .then((resp) => { | ||||||
|                     {$_('deselect-all')} |                                 current_runners = current_runners.filter((obj) => obj.id !== runner.id); | ||||||
|                   {:else}{$_('select-all')}{/if} |                               }) | ||||||
|                 </span> |                               .catch((err) => {}); | ||||||
|               </th> |                           }} | ||||||
|               <th |                           tabindex="0" | ||||||
|                 scope="col" |                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button> | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |                       </td> | ||||||
|                 {$_('name')} |                     {:else} | ||||||
|               </th> |                       <td | ||||||
|               <th |                         class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|                 scope="col" |                         <a | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |                           href="./{runner.id}" | ||||||
|                 {$_('contact-information')} |                           class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a> | ||||||
|               </th> |                         {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:DELETE')} | ||||||
|               <th |                           <button | ||||||
|                 scope="col" |                             on:click={() => { | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |                               active_deletes[runner.id] = true; | ||||||
|                 {$_('group')} |                             }} | ||||||
|               </th> |                             tabindex="0" | ||||||
|               <th |                             class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button> | ||||||
|                 scope="col" |                         {/if} | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |                       </td> | ||||||
|                 {$_('distance-in-km')} |                     {/if} | ||||||
|               </th> |                   </tr> | ||||||
|               <th scope="col" class="relative px-6 py-3"> |                 {/if} | ||||||
|                 <span class="sr-only">{$_('action')}</span> |               {/if} | ||||||
|               </th> |             {/each} | ||||||
|             </tr> |           </tbody> | ||||||
|           </thead> |         </table> | ||||||
|           <tbody class="divide-y divide-gray-200"> |       </div> | ||||||
|             {#each current_runners as runner} |     {/if} | ||||||
|               {#if runner.firstname |   {:catch error} | ||||||
|                 .toLowerCase() |     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> | ||||||
|                 .includes( |       <span class="inline-block align-middle mr-8"> | ||||||
|                   searchvalue.toLowerCase() |         <b class="capitalize">{$_('general_promise_error')}</b> | ||||||
|                 ) || runner.middlename |         {error} | ||||||
|                   .toLowerCase() |       </span> | ||||||
|                   .includes( |     </div> | ||||||
|                     searchvalue.toLowerCase() |   {/await} | ||||||
|                   ) || runner.lastname | {/if} | ||||||
|                   .toLowerCase() |  | ||||||
|                   .includes( |  | ||||||
|                     searchvalue.toLowerCase() |  | ||||||
|                   ) || should_display_based_on_id(runner.id)} |  | ||||||
|                 {#if filterGroupIDs.includes(runner.group.id) || filterGroupIDs.includes(runner.group.parentGroup?.id) || filterGroupIDs.length === 0} |  | ||||||
|                   <tr |  | ||||||
|                     data-rowid="user_{runner.id}" |  | ||||||
|                     data-groupid={runner.group.id}> |  | ||||||
|                     <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                       <input |  | ||||||
|                         bind:checked={runner.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"> |  | ||||||
|                         <div class="ml-4"> |  | ||||||
|                           <div class="text-sm font-medium text-gray-900"> |  | ||||||
|                             {runner.firstname} |  | ||||||
|                             {runner.middlename || ''} |  | ||||||
|                             {runner.lastname} |  | ||||||
|                           </div> |  | ||||||
|                         </div> |  | ||||||
|                       </div> |  | ||||||
|                     </td> |  | ||||||
|                     <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                       {#if runner.email} |  | ||||||
|                         <div class="text-sm text-gray-500">{runner.email}</div> |  | ||||||
|                       {/if} |  | ||||||
|                       {#if runner.phone} |  | ||||||
|                         <div class="text-sm text-gray-500">{runner.phone}</div> |  | ||||||
|                       {/if} |  | ||||||
|                       {#if runner.address.address1 !== null} |  | ||||||
|                         {runner.address.address1}<br /> |  | ||||||
|                         {runner.address.address2 || ''}<br /> |  | ||||||
|                         {runner.address.postalcode} |  | ||||||
|                         {runner.address.city} |  | ||||||
|                         {runner.address.country} |  | ||||||
|                       {/if} |  | ||||||
|                     </td> |  | ||||||
|                     <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                       {#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> |  | ||||||
|                       {/if} |  | ||||||
|                       {#if runner.group.responseType === 'RUNNERORGANIZATION'} |  | ||||||
|                         <a |  | ||||||
|                           href="../orgs/{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> |  | ||||||
|                       {/if} |  | ||||||
|                     </td> |  | ||||||
|                     <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                       {runner.distance} |  | ||||||
|                     </td> |  | ||||||
|                     {#if active_deletes[runner.id] === true} |  | ||||||
|                       <td |  | ||||||
|                         class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> |  | ||||||
|                         <button |  | ||||||
|                           on:click={() => { |  | ||||||
|                             active_deletes[runner.id] = false; |  | ||||||
|                           }} |  | ||||||
|                           tabindex="0" |  | ||||||
|                           class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button> |  | ||||||
|                         <button |  | ||||||
|                           on:click={() => { |  | ||||||
|                             RunnerService.runnerControllerRemove(runner.id, true) |  | ||||||
|                               .then((resp) => { |  | ||||||
|                                 current_runners = current_runners.filter((obj) => obj.id !== runner.id); |  | ||||||
|                               }) |  | ||||||
|                               .catch((err) => {}); |  | ||||||
|                           }} |  | ||||||
|                           tabindex="0" |  | ||||||
|                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button> |  | ||||||
|                       </td> |  | ||||||
|                     {:else} |  | ||||||
|                       <td |  | ||||||
|                         class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> |  | ||||||
|                         <a |  | ||||||
|                           href="./{runner.id}" |  | ||||||
|                           class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a> |  | ||||||
|                         {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:DELETE')} |  | ||||||
|                           <button |  | ||||||
|                             on:click={() => { |  | ||||||
|                               active_deletes[runner.id] = true; |  | ||||||
|                             }} |  | ||||||
|                             tabindex="0" |  | ||||||
|                             class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button> |  | ||||||
|                         {/if} |  | ||||||
|                       </td> |  | ||||||
|                     {/if} |  | ||||||
|                   </tr> |  | ||||||
|                 {/if} |  | ||||||
|               {/if} |  | ||||||
|             {/each} |  | ||||||
|           </tbody> |  | ||||||
|         </table> |  | ||||||
|       </div> |  | ||||||
|     {/if} |  | ||||||
|   {:catch error} |  | ||||||
|     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> |  | ||||||
|       <span class="inline-block align-middle mr-8"> |  | ||||||
|         <b class="capitalize">{$_('general_promise_error')}</b> |  | ||||||
|         {error} |  | ||||||
|       </span> |  | ||||||
|     </div> |  | ||||||
|   {/await} |  | ||||||
| {/if} |  | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|  |  | ||||||
| <div class="text-center items-center justify-center"> | <div class="text-center items-center justify-center"> | ||||||
|   <p class="mb-16 text-lg text-gray-500"> |   <p class="mb-16 text-lg text-gray-500"> | ||||||
|     <img class="w-full" style="height:15rem" src={scans_empty} alt="" /> |     <img class="m-auto" style="height:15rem" src={scans_empty} alt="" /> | ||||||
|     <span class="font-bold">{$_('there-are-no-scans-yet')}</span><br /> |     <span class="font-bold">{$_('there-are-no-scans-yet')}</span><br /> | ||||||
|     <span>{$_('add-your-fist-scan')}</span> |     <span>{$_('add-your-fist-scan')}</span> | ||||||
|   </p> |   </p> | ||||||
|   | |||||||
| @@ -81,10 +81,6 @@ | |||||||
|                 .includes( |                 .includes( | ||||||
|                   searchvalue.toLowerCase() |                   searchvalue.toLowerCase() | ||||||
|                 ) || scan.runner?.firstname |                 ) || scan.runner?.firstname | ||||||
|                   .toLowerCase() |  | ||||||
|                   .includes( |  | ||||||
|                     searchvalue.toLowerCase() |  | ||||||
|                   ) || scan.runner?.middlename |  | ||||||
|                   .toLowerCase() |                   .toLowerCase() | ||||||
|                   .includes( |                   .includes( | ||||||
|                     searchvalue.toLowerCase() |                     searchvalue.toLowerCase() | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| <svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="598.11" height="535.11"><path d="M3.35 120.07a4.6 4.6 0 00-3.18 5.66l76.72 273.98a4.6 4.6 0 005.65 3.18l282.82-79.19a4.6 4.6 0 003.18-5.66L291.82 44.07a4.6 4.6 0 00-5.65-3.19z" fill="#e6e6e6"/><path d="M86.1 389.95l269.5-75.46-72.99-260.67-269.5 75.46z" fill="#fff"/><path d="M48.74 164.1c-1.8.5-2.54 3.48-1.65 6.65s3.07 5.33 4.87 4.83l122.91-34.42c1.8-.5 2.54-3.49 1.66-6.65s-3.08-5.34-4.87-4.84zM58.64 199.44c-1.8.5-2.54 3.5-1.65 6.66s3.07 5.34 4.87 4.83l122.91-34.42c1.8-.5 2.54-3.49 1.65-6.65s-3.07-5.34-4.86-4.83zM68.42 234.39c-1.8.5-2.54 3.49-1.65 6.66s3.07 5.33 4.87 4.83l122.92-34.42c1.8-.5 2.54-3.5 1.65-6.66s-3.07-5.33-4.87-4.83zM78.32 269.74c-1.8.5-2.54 3.49-1.65 6.66s3.07 5.33 4.87 4.83l122.92-34.42c1.8-.5 2.54-3.49 1.65-6.66s-3.07-5.33-4.87-4.83zM234.04 112.61a5.97 5.97 0 103.21 11.5l22.98-6.44a5.97 5.97 0 00-3.22-11.49zM243.74 147.28a5.97 5.97 0 103.22 11.49l22.98-6.43a5.97 5.97 0 00-3.22-11.5zM253.45 181.95a5.97 5.97 0 103.22 11.49l22.98-6.44a5.97 5.97 0 00-3.22-11.49zM263.16 216.61a5.97 5.97 0 003.21 11.5l22.98-6.44a5.97 5.97 0 00-3.21-11.49z" fill="#e6e6e6"/><path d="M272.43 276.7a7.6 7.6 0 104.1 14.64l29.28-8.2a7.6 7.6 0 00-4.1-14.64z" fill="#6c63ff"/><path fill="#e6e6e6" d="M85.9 307.81l216.66-60.67.54 1.93-216.67 60.67z"/><path fill="#a0616a" d="M520.2 506.07l-17.38 4.2-24.47-65.02 25.65-6.2 16.2 67.02z"/><path d="M472.85 535.11l-.12-.48a22.23 22.23 0 0116.37-26.8l34-8.23 5.33 22.08z" fill="#2f2e41"/><path fill="#a0616a" d="M443.28 517.91H425.4l-8.5-68.96h26.38v68.96z"/><path d="M447.6 535.01h-57.18v-.5a22.2 22.2 0 0122.2-22.2h34.99zM416.88 490.99l-17.36-206.87 71.86-13.25.28-.05 21.03 13.52-7.32 76.14 33.7 118.7-29.1 7.65-33.75-110.08-7.73-33.48-3.96 43.5 2.94 107.28z" fill="#2f2e41"/><path d="M397.3 288.81l-.2-.24 24.84-186.96.03-.24.17-.18c.37-.36 9.07-8.96 18.02-8.96 1.3 0 2.52-.03 3.7-.06 6.85-.18 12.26-.32 18.69 6.1 6.55 6.56 27.92 30.47 27.92 63.23 0 31.7 2.88 130.22 2.91 131.21l.04 1.4-1.16-.76c-.3-.19-29.03-18.49-53.14-1.48-7.53 5.32-14.3 7.18-20.09 7.18-13.47 0-21.62-10.1-21.73-10.24z" fill="#6c63ff"/><circle cx="737.3" cy="227.82" r="35.82" transform="rotate(-28.66 229.78 725.57)" fill="#a0616a"/><path d="M381.53 328.99a14.66 14.66 0 00.85-22.47l20.34-47.97-26.63 4.9-15.23 44.8A14.74 14.74 0 00381.53 329z" fill="#a0616a"/><path d="M361.88 291.67l6.55-13.83a2.7 2.7 0 01-.97-1c-6.12-10.6 30.84-98.67 33.3-104.51-.37-3.18-4.25-36.85-1.41-48.2 3.34-13.35 10.2-19.58 22.93-20.81 14.04-1.32 17.83 17.75 17.86 17.94l.02 49.02-16.12 56.43-36.75 74.97z" fill="#6c63ff"/><path d="M440.94 58.87c-4.3.56-7.54-3.83-9.04-7.9s-2.64-8.78-6.38-10.98c-5.1-3-11.62.61-17.45-.38-6.59-1.11-10.87-8.1-11.2-14.76s2.31-13.1 4.92-19.24l.9 7.64A15.16 15.16 0 01409.33 0l-1.17 11.22c.73-6.29 7.5-11.16 13.7-9.85l-.19 6.68c7.6-.9 15.28-1.81 22.91-1.12s15.31 3.1 21.1 8.13c8.64 7.51 11.8 19.89 10.74 31.3s-5.77 22.13-10.68 32.48c-1.23 2.6-2.94 5.54-5.8 5.88-2.58.3-4.93-1.86-5.73-4.32s-.41-5.14.07-7.69c.72-3.84 1.63-7.77.95-11.63s-3.45-7.66-7.33-8.13-7.86 3.97-6 7.4z" fill="#2f2e41"/><path fill="#3f3d56" d="M597.73 535.1H339.99v-2.11h258.12l-.38 2.1z"/></svg> | <svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 647.6 632.2"><path d="M411 142H237a15 15 0 00-15 15v388l-2 1-43 13a8 8 0 01-10-6L39 137a8 8 0 016-10l66-20 191-58 66-20a8 8 0 0110 5l33 106z" fill="#f2f2f2"/><path d="M449 140L410 12a17 17 0 00-21-11l-93 28-191 59-93 28a17 17 0 00-11 21l134 438a17 17 0 0016 12 17 17 0 005 0l64-20 2-1v-2l-2 1-65 20a15 15 0 01-18-10L3 137a15 15 0 0110-19l92-28 192-59 92-28a15 15 0 015-1 15 15 0 0114 11l39 127 1 2h2z" fill="#3f3d56"/><path d="M123 128a9 9 0 01-9-7l-13-42a9 9 0 016-11l176-54a9 9 0 0111 6l13 42a9 9 0 01-6 12l-176 53a9 9 0 01-2 1z" fill="#6c63ff"/><circle cx="190.2" cy="25" r="20" fill="#6c63ff"/><circle cx="190.2" cy="25" r="12.7" fill="#fff"/><path d="M603 582H265a9 9 0 01-9-8V169a9 9 0 019-9h338a9 9 0 018 9v405a9 9 0 01-8 8z" fill="#e6e6e6"/><path d="M447 140H237a17 17 0 00-17 17v408l2-1V157a15 15 0 0115-15h211zm184 0H237a17 17 0 00-17 17v458a17 17 0 0017 17h394a17 17 0 0017-17V157a17 17 0 00-17-17zm15 475a15 15 0 01-15 15H237a15 15 0 01-15-15V157a15 15 0 0115-15h394a15 15 0 0115 15z" fill="#3f3d56"/><path d="M526 184H342a9 9 0 01-9-9v-44a9 9 0 019-9h184a9 9 0 019 9v44a9 9 0 01-9 9z" fill="#6c63ff"/><circle cx="433.6" cy="105.2" r="20" fill="#6c63ff"/><circle cx="433.6" cy="105.2" r="12.2" fill="#fff"/></svg> | ||||||
| Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.3 KiB | 
| @@ -86,7 +86,7 @@ | |||||||
|               <div class="mt-2 mb-6"> |               <div class="mt-2 mb-6"> | ||||||
|                 <label |                 <label | ||||||
|                   for="token" |                   for="token" | ||||||
|                   class="block text-sm font-medium text-gray-700">Token</label> |                   class="block text-sm font-medium text-gray-700">{$_('token')}</label> | ||||||
|                 <div on:click={copy} class="inline-flex"> |                 <div on:click={copy} class="inline-flex"> | ||||||
|                   <p |                   <p | ||||||
|                     name="token" |                     name="token" | ||||||
|   | |||||||
| @@ -1,399 +1,297 @@ | |||||||
| <script> | <script> | ||||||
|   import { |   import { | ||||||
|     GroupContactService, |     GroupContactService, | ||||||
|     RunnerOrganizationService, |     RunnerOrganizationService, | ||||||
|     RunnerTeamService, |     RunnerTeamService, | ||||||
|   } from "@odit/lfk-client-js"; |   } from "@odit/lfk-client-js"; | ||||||
|   import { getLocaleFromNavigator, _ } from "svelte-i18n"; |   import { getLocaleFromNavigator, _ } from "svelte-i18n"; | ||||||
|   import Toastify from "toastify-js"; |   import Toastify from "toastify-js"; | ||||||
|   import store from "../../store"; |   import store from "../../store"; | ||||||
|   import Select from "svelte-select"; |   import Select from "svelte-select"; | ||||||
|   import ImportRunnerModal from "../runners/ImportRunnerModal.svelte"; |   import ImportRunnerModal from "../runners/ImportRunnerModal.svelte"; | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; |   import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   import ConfirmTeamDeletion from "./ConfirmTeamDeletion.svelte"; |   import ConfirmTeamDeletion from "./ConfirmTeamDeletion.svelte"; | ||||||
| import Teams from "./Teams.svelte"; |   import Teams from "./Teams.svelte"; | ||||||
|   let [teamdata, original, delete_team, orgs, contacts, modal_open] = [ |   import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | ||||||
|     {}, |   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|     {}, |   let [teamdata, original, delete_team, orgs, contacts, modal_open] = [ | ||||||
|     {}, |     {}, | ||||||
|     [], |     {}, | ||||||
|     [], |     {}, | ||||||
|     false, |     [], | ||||||
|   ]; |     [], | ||||||
|   export let params; |     false, | ||||||
|   export let import_modal_open = false; |   ]; | ||||||
|   $: delete_triggered = false; |   export let params; | ||||||
|   $: save_enabled = !data_changed && teamdata.parentGroup != null; |   export let import_modal_open = false; | ||||||
|   $: data_loaded = false; |   $: delete_triggered = false; | ||||||
|   $: data_changed = JSON.stringify(teamdata) === JSON.stringify(original); |   $: save_enabled = !data_changed && teamdata.parentGroup != null; | ||||||
|   $: sponsoring_contracts_download_open = false; |   $: data_loaded = false; | ||||||
|   $: group = {}; |   $: data_changed = JSON.stringify(teamdata) === JSON.stringify(original); | ||||||
|   $: contact = {}; |   $: sponsoring_contracts_show = true; | ||||||
|   // |   $: cards_show = true; | ||||||
|   const getContactLabel = (option) => |   $: generate_teams = [original]; | ||||||
|     option.firstname + " " + (option.middlename || "") + " " + option.lastname; |   $: group = {}; | ||||||
|   const promise = RunnerTeamService.runnerTeamControllerGetOne( |   $: contact = {}; | ||||||
|     params.teamid |   // | ||||||
|   ).then((value) => { |   const getContactLabel = (option) => | ||||||
|     data_loaded = true; |     option.firstname + " " + (option.middlename || "") + " " + option.lastname; | ||||||
|     teamdata = Object.assign(teamdata, value); |   const promise = RunnerTeamService.runnerTeamControllerGetOne( | ||||||
|     original = Object.assign(original, value); |     params.teamid | ||||||
|     RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => { |   ).then((value) => { | ||||||
|       orgs = val.map((r) => { |     data_loaded = true; | ||||||
|         return { label: r.name, value: r }; |     teamdata = Object.assign(teamdata, value); | ||||||
|       }); |     original = Object.assign(original, value); | ||||||
|       group = orgs.find((g) => g.value.id == teamdata.parentGroup.id); |     RunnerOrganizationService.runnerOrganizationControllerGetAll().then( | ||||||
|     }); |       (val) => { | ||||||
|     GroupContactService.groupContactControllerGetAll().then((val) => { |         orgs = val.map((r) => { | ||||||
|       contacts = val.map((r) => { |           return { label: r.name, value: r }; | ||||||
|         return { label: getContactLabel(r), value: r }; |         }); | ||||||
|       }); |         group = orgs.find((g) => g.value.id == teamdata.parentGroup.id); | ||||||
|       if(teamdata.contact){ |       } | ||||||
|         contact = contacts.find((g) => g.value.id == teamdata.contact.id); |     ); | ||||||
|       } |     GroupContactService.groupContactControllerGetAll().then((val) => { | ||||||
|       else{ |       contacts = val.map((r) => { | ||||||
|         contact = null; |         return { label: getContactLabel(r), value: r }; | ||||||
|       } |       }); | ||||||
|     }); |       if (teamdata.contact) { | ||||||
|   }); |         contact = contacts.find((g) => g.value.id == teamdata.contact.id); | ||||||
|   document.addEventListener("click", function (e) { |       } else { | ||||||
|     if ( |         contact = null; | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown" && |       } | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown:menu" |     }); | ||||||
|     ) { |   }); | ||||||
|       sponsoring_contracts_download_open = false; |   function deleteTeam() { | ||||||
|     } |     RunnerTeamService.runnerTeamControllerRemove(original.id, false) | ||||||
|   }); |       .then((resp) => { | ||||||
|   function deleteTeam() { |         Toastify({ | ||||||
|     RunnerTeamService.runnerTeamControllerRemove(original.id, false) |           text: "Organization deleted", | ||||||
|       .then((resp) => { |           duration: 500, | ||||||
|         Toastify({ |           backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|           text: "Organization deleted", |         }).showToast(); | ||||||
|           duration: 500, |         location.replace("./"); | ||||||
|           backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", |       }) | ||||||
|         }).showToast(); |       .catch((err) => { | ||||||
|         location.replace("./"); |         modal_open = true; | ||||||
|       }) |         delete_team = original; | ||||||
|       .catch((err) => { |       }); | ||||||
|         modal_open = true; |   } | ||||||
|         delete_team = original; |   function submit() { | ||||||
|       }); |     if (data_loaded === true && save_enabled) { | ||||||
|   } |       Toastify({ | ||||||
|   function submit() { |         text: "updating team", | ||||||
|     if (data_loaded === true && save_enabled) { |         duration: 2500, | ||||||
|       Toastify({ |       }).showToast(); | ||||||
|         text: "updating team", |       let postdata = teamdata; | ||||||
|         duration: 2500, |       postdata.parentGroup = teamdata.parentGroup.id; | ||||||
|       }).showToast(); |       postdata.contact = teamdata.contact?.id; | ||||||
|       let postdata = teamdata; |       RunnerTeamService.runnerTeamControllerPut(original.id, postdata) | ||||||
|       postdata.parentGroup = teamdata.parentGroup.id; |         .then((resp) => { | ||||||
|       postdata.contact = teamdata.contact?.id; |           Object.assign(original, teamdata); | ||||||
|       RunnerTeamService.runnerTeamControllerPut(original.id, postdata) |           original = original; | ||||||
|         .then((resp) => { |           Toastify({ | ||||||
|           Object.assign(original, teamdata); |             text: "updated team", | ||||||
|           original = original; |             duration: 2500, | ||||||
|           Toastify({ |             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", | ||||||
|             text: "updated team", |           }).showToast(); | ||||||
|             duration: 2500, |         }) | ||||||
|             backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", |         .catch((err) => {}); | ||||||
|           }).showToast(); |     } | ||||||
|         }) |   } | ||||||
|         .catch((err) => {}); | </script> | ||||||
|     } |  | ||||||
|   } | <ImportRunnerModal | ||||||
|   async function generateSponsoringContract(locale) { |   current_runners={[]} | ||||||
|     sponsoring_contracts_download_open = false; |   on:cancelDelete={(event) => { | ||||||
|     const runners = await RunnerTeamService.runnerTeamControllerGetRunners( |     import_modal_open = false; | ||||||
|       teamdata.id |   }} | ||||||
|     ); |   passed_team={teamdata} | ||||||
|     const toast = Toastify({ |   passed_orgs={[]} | ||||||
|       text: $_("generating-pdf"), |   passed_org={{}} | ||||||
|       duration: -1, |   opened_from="TeamDetail" | ||||||
|     }).showToast(); |   bind:import_modal_open /> | ||||||
|     fetch( | <ConfirmTeamDeletion bind:modal_open bind:delete_team /> | ||||||
|       `https://dev.lauf-fuer-kaya.de/documents/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, | {#if data_loaded} | ||||||
|       { |   <section class="container p-5"> | ||||||
|         method: "POST", |     <div class="mb-8 text-3xl font-extrabold leading-tight"> | ||||||
|         headers: { |       {original.name} | ||||||
|           "Content-Type": "application/json", |       <span data-id="org_actions_${teamdata.id}"> | ||||||
|         }, |         <GenerateSponsoringContracts | ||||||
|         body: JSON.stringify(runners), |           bind:sponsoring_contracts_show | ||||||
|       } |           bind:generate_teams /> | ||||||
|     ) |         <GenerateRunnerCards | ||||||
|       .then((response) => { |           bind:cards_show | ||||||
|         if (response.status != "200") { |           bind:generate_teams /> | ||||||
|           toast.hideToast(); |         {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')} | ||||||
|           Toastify({ |           <button | ||||||
|             text: $_("pdf-generation-failed"), |             on:click={() => { | ||||||
|             duration: 3500, |               import_modal_open = true; | ||||||
|             backgroundColor: |             }} | ||||||
|               "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", |             type="button" | ||||||
|           }).showToast(); |             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"> | ||||||
|         } else { |             {$_('import-runners')} | ||||||
|           return response.blob(); |           </button> | ||||||
|         } |         {/if} | ||||||
|       }) |         {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:DELETE')} | ||||||
|       .then((blob) => { |           {#if delete_triggered} | ||||||
|         const url = window.URL.createObjectURL(blob); |             <button | ||||||
|         let a = document.createElement("a"); |               on:click={deleteTeam} | ||||||
|         a.href = url; |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('confirm-delete')}</button> | ||||||
|         a.download = "Sponsorings_" + teamdata.name + ".pdf"; |             <button | ||||||
|         document.body.appendChild(a); |               on:click={() => { | ||||||
|         a.click(); |                 delete_triggered = !delete_triggered; | ||||||
|         a.remove(); |               }} | ||||||
|         toast.hideToast(); |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm">{$_('cancel')}</button> | ||||||
|         Toastify({ |           {/if} | ||||||
|           text: $_("pdf-successfully-generated"), |           {#if !delete_triggered} | ||||||
|           duration: 3500, |             <button | ||||||
|           backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", |               on:click={() => { | ||||||
|         }).showToast(); |                 delete_triggered = true; | ||||||
|       }) |               }} | ||||||
|       .catch((err) => {}); |               type="button" | ||||||
|   } |               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('delete-team')}</button> | ||||||
| </script> |           {/if} | ||||||
|  |         {/if} | ||||||
| <ImportRunnerModal |         {#if !delete_triggered} | ||||||
|   current_runners={[]} |           <button | ||||||
|   on:cancelDelete={(event) => { |             on:click={submit} | ||||||
|     import_modal_open = false; |             disabled={!save_enabled} | ||||||
|   }} |             class:opacity-50={!save_enabled} | ||||||
|   passed_team={teamdata} |             type="button" | ||||||
|   passed_orgs={[]} |             class="w-full 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> | ||||||
|   passed_org={{}} |         {/if} | ||||||
|   opened_from="TeamDetail" |       </span> | ||||||
|   bind:import_modal_open /> |     </div> | ||||||
| <ConfirmTeamDeletion bind:modal_open bind:delete_team /> |     <div class="flex flex-row mb-4"> | ||||||
| {#if data_loaded} |       <div class="w-full"> | ||||||
|   <section class="container p-5"> |         <nav class="w-full flex"> | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> |           <ol class="list-none flex flex-row items-center justify-start"> | ||||||
|       {original.name} |             <li class="mr-2 flex items-center"> | ||||||
|       <span data-id="org_actions_${teamdata.id}"> |               <svg | ||||||
|         <div id="sponsoring:dropdown" class="relative inline-block"> |                 stroke="currentColor" | ||||||
|           <div> |                 fill="none" | ||||||
|             <button |                 stroke-width="2" | ||||||
|               on:click={() => { |                 viewBox="0 0 24 24" | ||||||
|                 sponsoring_contracts_download_open = !sponsoring_contracts_download_open; |                 stroke-linecap="round" | ||||||
|               }} |                 stroke-linejoin="round" | ||||||
|               type="button" |                 class="h-3 w-3 stroke-current" | ||||||
|               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" |                 height="1em" | ||||||
|               id="options-menu" |                 width="1em" | ||||||
|               aria-haspopup="true" |                 xmlns="http://www.w3.org/2000/svg"><path | ||||||
|               aria-expanded="true"> |                   d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /> | ||||||
|               {$_('generate-sponsoring-contracts')} |                 <polyline points="9 22 9 12 15 12 15 22" /></svg> | ||||||
|               <svg |             </li> | ||||||
|                 xmlns="http://www.w3.org/2000/svg" |             <li class="flex items-center"> | ||||||
|                 width="24" |               <a class="mr-2" href="/">Home</a><svg | ||||||
|                 height="24" |                 stroke="currentColor" | ||||||
|                 viewBox="0 0 24 24" |                 fill="none" | ||||||
|                 class="-mr-1 ml-2 h-5 w-5"><path |                 stroke-width="2" | ||||||
|                   fill="none" |                 viewBox="0 0 24 24" | ||||||
|                   d="M0 0h24v24H0z" /> |                 stroke-linecap="round" | ||||||
|                 <path |                 stroke-linejoin="round" | ||||||
|                   fill="currentColor" |                 class="h-3 w-3 mr-2 stroke-current" | ||||||
|                   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> |                 height="1em" | ||||||
|             </button> |                 width="1em" | ||||||
|           </div> |                 xmlns="http://www.w3.org/2000/svg"><line | ||||||
|           {#if sponsoring_contracts_download_open} |                   x1="5" | ||||||
|             <div |                   y1="12" | ||||||
|               class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5" |                   x2="19" | ||||||
|               id="sponsoring:dropdown:menu"> |                   y2="12" /> | ||||||
|               <div |                 <polyline points="12 5 19 12 12 19" /></svg> | ||||||
|                 class="py-1" |             </li> | ||||||
|                 role="menu" |             <li class="mr-2 flex items-center"> | ||||||
|                 aria-orientation="vertical" |               <svg | ||||||
|                 aria-labelledby="options-menu"> |                 class="flex-shrink-0 w-5 h-5 mr-2" | ||||||
|                 <span |                 fill="currentColor" | ||||||
|                   class="block w-full text-left px-4 py-2 text-sm text-gray-700">{$_('select-language')}</span> |                 width="24" | ||||||
|                 <button |                 height="24" | ||||||
|                   on:click={() => { |                 xmlns="http://www.w3.org/2000/svg" | ||||||
|                     generateSponsoringContract('de'); |                 viewBox="0 0 640 512"><path | ||||||
|                   }} |                   fill="currentColor" | ||||||
|                   type="submit" |                   d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg> | ||||||
|                   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 inline-flex" |             </li> | ||||||
|                   role="menuitem"> |             <li class="flex items-center"> | ||||||
|                   {$_('german')} |               <a class="mr-2" href="./">Teams</a><svg | ||||||
|                 </button> |                 stroke="currentColor" | ||||||
|                 <button |                 fill="none" | ||||||
|                   on:click={() => { |                 stroke-width="2" | ||||||
|                     generateSponsoringContract('en'); |                 viewBox="0 0 24 24" | ||||||
|                   }} |                 stroke-linecap="round" | ||||||
|                   type="submit" |                 stroke-linejoin="round" | ||||||
|                   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 inline-flex" |                 class="h-3 w-3 mr-2 stroke-current" | ||||||
|                   role="menuitem"> |                 height="1em" | ||||||
|                   {$_('english')} |                 width="1em" | ||||||
|                 </button> |                 xmlns="http://www.w3.org/2000/svg"><line | ||||||
|               </div> |                   x1="5" | ||||||
|             </div> |                   y1="12" | ||||||
|           {/if} |                   x2="19" | ||||||
|         </div> |                   y2="12" /> | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')} |                 <polyline points="12 5 19 12 12 19" /></svg> | ||||||
|           <button |             </li> | ||||||
|             on:click={() => { |             <li class="flex items-center"> | ||||||
|               import_modal_open = true; |               <span class="mr-2">Team-Details #{params.teamid}</span> | ||||||
|             }} |             </li> | ||||||
|             type="button" |           </ol> | ||||||
|             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"> |         </nav> | ||||||
|             {$_('import-runners')} |       </div> | ||||||
|           </button> |     </div> | ||||||
|         {/if} |     <div class="text-sm w-full"> | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:DELETE')} |       <label for="name" class="font-medium text-gray-700">Name</label> | ||||||
|           {#if delete_triggered} |       <input | ||||||
|             <button |         autocomplete="off" | ||||||
|               on:click={deleteTeam} |         placeholder="Name" | ||||||
|               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('confirm-delete')}</button> |         type="text" | ||||||
|             <button |         bind:value={teamdata.name} | ||||||
|               on:click={() => { |         name="name" | ||||||
|                 delete_triggered = !delete_triggered; |         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> | ||||||
|               }} |     </div> | ||||||
|               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm">{$_('cancel')}</button> |     <div class="text-sm w-full"> | ||||||
|           {/if} |       <label | ||||||
|           {#if !delete_triggered} |         for="contact" | ||||||
|             <button |         class="font-medium text-gray-700">{$_('contact')}</label> | ||||||
|               on:click={() => { |       <Select | ||||||
|                 delete_triggered = true; |         containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | ||||||
|               }} |         itemFilter={(label, filterText, option) => label | ||||||
|               type="button" |             .toLowerCase() | ||||||
|               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">{$_('delete-team')}</button> |             .includes( | ||||||
|           {/if} |               filterText.toLowerCase() | ||||||
|         {/if} |             ) || option.value.id | ||||||
|         {#if !delete_triggered} |             .toString() | ||||||
|           <button |             .startsWith(filterText.toLowerCase())} | ||||||
|             on:click={submit} |         items={contacts} | ||||||
|             disabled={!save_enabled} |         showChevron={true} | ||||||
|             class:opacity-50={!save_enabled} |         placeholder={$_('no-contact-selected')} | ||||||
|             type="button" |         noOptionsMessage={$_('no-contact-found')} | ||||||
|             class="w-full 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> |         bind:selectedValue={contact} | ||||||
|         {/if} |         on:select={(selectedValue) => (teamdata.contact = selectedValue.detail.value)} | ||||||
|       </span> |         on:clear={() => (teamdata.contact = null)} /> | ||||||
|     </div> |     </div> | ||||||
|     <div class="flex flex-row mb-4"> |     <div class="text-sm w-full"> | ||||||
|       <div class="w-full"> |       <label | ||||||
|         <nav class="w-full flex"> |         for="org" | ||||||
|           <ol class="list-none flex flex-row items-center justify-start"> |         class="font-medium text-gray-700">{$_('organization')}</label> | ||||||
|             <li class="mr-2 flex items-center"> |       <Select | ||||||
|               <svg |         containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | ||||||
|                 stroke="currentColor" |         itemFilter={(label, filterText, option) => label | ||||||
|                 fill="none" |             .toLowerCase() | ||||||
|                 stroke-width="2" |             .includes( | ||||||
|                 viewBox="0 0 24 24" |               filterText.toLowerCase() | ||||||
|                 stroke-linecap="round" |             ) || option.id.value | ||||||
|                 stroke-linejoin="round" |             .toString() | ||||||
|                 class="h-3 w-3 stroke-current" |             .startsWith(filterText.toLowerCase())} | ||||||
|                 height="1em" |         items={orgs} | ||||||
|                 width="1em" |         showChevron={true} | ||||||
|                 xmlns="http://www.w3.org/2000/svg"><path |         placeholder={$_('search-for-an-organization-by-name-or-id')} | ||||||
|                   d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /> |         noOptionsMessage={$_('no-organizations-found')} | ||||||
|                 <polyline points="9 22 9 12 15 12 15 22" /></svg> |         bind:selectedValue={group} | ||||||
|             </li> |         on:select={(selectedValue) => (teamdata.parentGroup = selectedValue.detail.value)} | ||||||
|             <li class="flex items-center"> |         on:clear={() => (teamdata.parentGroup = null)} /> | ||||||
|               <a class="mr-2" href="/">Home</a><svg |     </div> | ||||||
|                 stroke="currentColor" |   </section> | ||||||
|                 fill="none" | {:else} | ||||||
|                 stroke-width="2" |   {#await promise} | ||||||
|                 viewBox="0 0 24 24" |     {$_('team-detail-is-being-loaded')} | ||||||
|                 stroke-linecap="round" |   {:catch error} | ||||||
|                 stroke-linejoin="round" |     <PromiseError /> | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" |   {/await} | ||||||
|                 height="1em" | {/if} | ||||||
|                 width="1em" |  | ||||||
|                 xmlns="http://www.w3.org/2000/svg"><line |  | ||||||
|                   x1="5" |  | ||||||
|                   y1="12" |  | ||||||
|                   x2="19" |  | ||||||
|                   y2="12" /> |  | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg> |  | ||||||
|             </li> |  | ||||||
|             <li class="mr-2 flex items-center"> |  | ||||||
|               <svg |  | ||||||
|                 class="flex-shrink-0 w-5 h-5 mr-2" |  | ||||||
|                 fill="currentColor" |  | ||||||
|                 width="24" |  | ||||||
|                 height="24" |  | ||||||
|                 xmlns="http://www.w3.org/2000/svg" |  | ||||||
|                 viewBox="0 0 640 512"><path |  | ||||||
|                   fill="currentColor" |  | ||||||
|                   d="M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z" /></svg> |  | ||||||
|             </li> |  | ||||||
|             <li class="flex items-center"> |  | ||||||
|               <a class="mr-2" href="./">Teams</a><svg |  | ||||||
|                 stroke="currentColor" |  | ||||||
|                 fill="none" |  | ||||||
|                 stroke-width="2" |  | ||||||
|                 viewBox="0 0 24 24" |  | ||||||
|                 stroke-linecap="round" |  | ||||||
|                 stroke-linejoin="round" |  | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" |  | ||||||
|                 height="1em" |  | ||||||
|                 width="1em" |  | ||||||
|                 xmlns="http://www.w3.org/2000/svg"><line |  | ||||||
|                   x1="5" |  | ||||||
|                   y1="12" |  | ||||||
|                   x2="19" |  | ||||||
|                   y2="12" /> |  | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg> |  | ||||||
|             </li> |  | ||||||
|             <li class="flex items-center"> |  | ||||||
|               <span class="mr-2">Team-Details #{params.teamid}</span> |  | ||||||
|             </li> |  | ||||||
|           </ol> |  | ||||||
|         </nav> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|     <div class="text-sm w-full"> |  | ||||||
|       <label for="name" class="font-medium text-gray-700">Name</label> |  | ||||||
|       <input |  | ||||||
|         autocomplete="off" |  | ||||||
|         placeholder="Name" |  | ||||||
|         type="text" |  | ||||||
|         bind:value={teamdata.name} |  | ||||||
|         name="name" |  | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" /> |  | ||||||
|     </div> |  | ||||||
|     <div class="text-sm w-full"> |  | ||||||
|       <label |  | ||||||
|         for="contact" |  | ||||||
|         class="font-medium text-gray-700">{$_('contact')}</label> |  | ||||||
|       <Select |  | ||||||
|         containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |  | ||||||
|         itemFilter={(label, filterText, option) => label |  | ||||||
|             .toLowerCase() |  | ||||||
|             .includes( |  | ||||||
|               filterText.toLowerCase() |  | ||||||
|             ) || option.value.id |  | ||||||
|             .toString() |  | ||||||
|             .startsWith(filterText.toLowerCase())} |  | ||||||
|         items={contacts} |  | ||||||
|         showChevron={true} |  | ||||||
|         placeholder={$_('no-contact-selected')} |  | ||||||
|         noOptionsMessage={$_('no-contact-found')} |  | ||||||
|         bind:selectedValue={contact} |  | ||||||
|         on:select={(selectedValue)=> teamdata.contact = selectedValue.detail.value} |  | ||||||
|         on:clear={() => (teamdata.contact = null)} /> |  | ||||||
|     </div> |  | ||||||
|     <div class="text-sm w-full"> |  | ||||||
|       <label |  | ||||||
|         for="org" |  | ||||||
|         class="font-medium text-gray-700">{$_('organization')}</label> |  | ||||||
|       <Select |  | ||||||
|         containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |  | ||||||
|         itemFilter={(label, filterText, option) => label |  | ||||||
|             .toLowerCase() |  | ||||||
|             .includes( |  | ||||||
|               filterText.toLowerCase() |  | ||||||
|             ) || option.id.value.toString().startsWith(filterText.toLowerCase())} |  | ||||||
|         items={orgs} |  | ||||||
|         showChevron={true} |  | ||||||
|         placeholder={$_('search-for-an-organization-by-name-or-id')} |  | ||||||
|         noOptionsMessage={$_('no-organizations-found')} |  | ||||||
|         bind:selectedValue={group} |  | ||||||
|         on:select={(selectedValue)=> teamdata.parentGroup = selectedValue.detail.value} |  | ||||||
|         on:clear={() => (teamdata.parentGroup = null)} /> |  | ||||||
|     </div> |  | ||||||
|   </section> |  | ||||||
| {:else} |  | ||||||
|   {#await promise} |  | ||||||
|     {$_('team-detail-is-being-loaded')} |  | ||||||
|   {:catch error} |  | ||||||
|     <PromiseError /> |  | ||||||
|   {/await} |  | ||||||
| {/if} |  | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> |   <span class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_('teams')} |     {$_('teams')} | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')} |     {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:CREATE')} | ||||||
|       <button |       <button | ||||||
|         on:click={() => { |         on:click={() => { | ||||||
|           modal_open = true; |           modal_open = true; | ||||||
| @@ -27,6 +27,6 @@ | |||||||
|   <TeamsOverview bind:current_teams /> |   <TeamsOverview bind:current_teams /> | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes('USER:CREATE')} | {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:CREATE')} | ||||||
|   <AddTeamModal bind:current_teams bind:modal_open /> |   <AddTeamModal bind:current_teams bind:modal_open /> | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -1,330 +1,217 @@ | |||||||
| <script> | <script> | ||||||
|   import { getLocaleFromNavigator, t, _ } from "svelte-i18n"; |   import { getLocaleFromNavigator, t, _ } from "svelte-i18n"; | ||||||
|   import Toastify from "toastify-js"; |   import Toastify from "toastify-js"; | ||||||
|   import { RunnerTeamService } from "@odit/lfk-client-js"; |   import { RunnerTeamService } from "@odit/lfk-client-js"; | ||||||
|   const teams_promise = RunnerTeamService.runnerTeamControllerGetAll(); |   const teams_promise = RunnerTeamService.runnerTeamControllerGetAll(); | ||||||
|   import store, { users as usersstore } from "../../store.js"; |   import store, { users as usersstore } from "../../store.js"; | ||||||
|   import TeamsEmptyState from "./TeamsEmptyState.svelte"; |   import TeamsEmptyState from "./TeamsEmptyState.svelte"; | ||||||
|   import ConfirmTeamDeletion from "./ConfirmTeamDeletion.svelte"; |   import ConfirmTeamDeletion from "./ConfirmTeamDeletion.svelte"; | ||||||
|   import { clickOutside } from "../base/outsideclick"; |   import { clickOutside } from "../base/outsideclick"; | ||||||
|   $: searchvalue = ""; |   import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | ||||||
|   $: active_deletes = []; |   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|   $: sponsoring_contracts_download_open = false; |   $: searchvalue = ""; | ||||||
|   export let current_teams = []; |   $: active_deletes = []; | ||||||
|   let modal_open = false; |   $: sponsoring_contracts_show = current_teams.some( | ||||||
|   let delete_team = {}; |     (r) => r.is_selected === true | ||||||
|   usersstore.subscribe((val) => { |   ); | ||||||
|     current_teams = val; |   $: cards_show = current_teams.some( | ||||||
|   }); |     (r) => r.is_selected === true | ||||||
|   teams_promise.then((data) => { |   ); | ||||||
|     usersstore.set(data); |   $: generate_teams = current_teams.filter((r) => r.is_selected === true); | ||||||
|   }); |   export let current_teams = []; | ||||||
|   document.addEventListener("click", function (e) { |   let modal_open = false; | ||||||
|       if ( |   let delete_team = {}; | ||||||
|         e.target.parentNode?.parentNode?.id != "sponsoring:dropdown" && |   usersstore.subscribe((val) => { | ||||||
|         e.target.parentNode?.parentNode?.id != "sponsoring:dropdown:menu" |     current_teams = val; | ||||||
|       ) { |   }); | ||||||
|         sponsoring_contracts_download_open = false; |   teams_promise.then((data) => { | ||||||
|       } |     usersstore.set(data); | ||||||
|   }); |   }); | ||||||
|   async function generateSponsoringContract(locale) { | </script> | ||||||
|     sponsoring_contracts_download_open = false; |  | ||||||
|     const teams = current_teams.filter((r) => r.is_selected === true); | <ConfirmTeamDeletion | ||||||
|     const toast = Toastify({ |   on:cancelDelete={(event) => { | ||||||
|       text: $_("generating-pdfs"), |     modal_open = false; | ||||||
|       duration: -1, |     active_deletes[event.detail.id] = false; | ||||||
|     }).showToast(); |   }} | ||||||
|     let count = 0; |   bind:modal_open | ||||||
|     for await (const t of teams) { |   bind:delete_team /> | ||||||
|       count++; | {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:GET')} | ||||||
|       const runners = await RunnerTeamService.runnerTeamControllerGetRunners( |   {#await teams_promise} | ||||||
|         t.id |     <div | ||||||
|       ); |       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|       fetch( |       role="alert"> | ||||||
|         `https://dev.lauf-fuer-kaya.de/documents/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, |       <p class="font-bold">{$_('teams-are-being-loaded')}</p> | ||||||
|         { |       <p class="text-sm">{$_('this-might-take-a-moment')}</p> | ||||||
|           method: "POST", |     </div> | ||||||
|           headers: { |   {:then} | ||||||
|             "Content-Type": "application/json", |     {#if current_teams.length === 0} | ||||||
|           }, |       <TeamsEmptyState /> | ||||||
|           body: JSON.stringify(runners), |     {:else} | ||||||
|         } |       <input | ||||||
|       ) |         type="search" | ||||||
|         .then((response) => { |         bind:value={searchvalue} | ||||||
|           if (response.status != "200") { |         placeholder={$_('datatable.search')} | ||||||
|             toast.hideToast(); |         aria-label={$_('datatable.search')} | ||||||
|             Toastify({ |         class="gridjs-input gridjs-search-input mb-4" /> | ||||||
|               text: $_("pdf-generation-failed"), |       <div class="h-12"> | ||||||
|               duration: 3500, |         <GenerateSponsoringContracts | ||||||
|               backgroundColor: |           bind:sponsoring_contracts_show | ||||||
|                 "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", |           bind:generate_teams /> | ||||||
|             }).showToast(); |         <GenerateRunnerCards | ||||||
|           } else { |           bind:cards_show | ||||||
|             return response.blob(); |           bind:generate_teams /> | ||||||
|           } |       </div> | ||||||
|         }) |       <div | ||||||
|         .then((blob) => { |         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> | ||||||
|           const url = window.URL.createObjectURL(blob); |         <table class="divide-y divide-gray-200 w-full"> | ||||||
|           let a = document.createElement("a"); |           <thead class="bg-gray-50"> | ||||||
|           a.href = url; |             <tr> | ||||||
|           a.download = "Sponsorings_" + t.name + ".pdf"; |               <th | ||||||
|           document.body.appendChild(a); |                 scope="col" | ||||||
|           a.click(); |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|           a.remove(); |                 <span | ||||||
|           if (count === teams.length) { |                   on:click={() => { | ||||||
|             toast.hideToast(); |                     const newstate = !current_teams.some((r) => r.is_selected === true); | ||||||
|             Toastify({ |                     current_teams = current_teams.map((r) => { | ||||||
|               text: $_("pdfs-successfully-generated"), |                       r.is_selected = newstate; | ||||||
|               duration: 3500, |                       return r; | ||||||
|               backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", |                     }); | ||||||
|             }).showToast(); |                   }} | ||||||
|           } |                   class="underline cursor-pointer select-none">{#if current_teams.some((r) => r.is_selected === true)} | ||||||
|         }) |                     {$_('deselect-all')} | ||||||
|         .catch((err) => {}); |                   {:else}{$_('select-all')}{/if} | ||||||
|     } |                 </span> | ||||||
|   } |               </th> | ||||||
| </script> |               <th | ||||||
|  |                 scope="col" | ||||||
| <ConfirmTeamDeletion |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|   on:cancelDelete={(event) => { |                 {$_('name')} | ||||||
|     modal_open = false; |               </th> | ||||||
|     active_deletes[event.detail.id] = false; |               <th | ||||||
|   }} |                 scope="col" | ||||||
|   bind:modal_open |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|   bind:delete_team /> |                 {$_('organization')} | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:GET')} |               </th> | ||||||
|   {#await teams_promise} |               <th | ||||||
|     <div |                 scope="col" | ||||||
|       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" |                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | ||||||
|       role="alert"> |                 {$_('contact')} | ||||||
|       <p class="font-bold">{$_('teams-are-being-loaded')}</p> |               </th> | ||||||
|       <p class="text-sm">{$_('this-might-take-a-moment')}</p> |               <th scope="col" class="relative px-6 py-3"> | ||||||
|     </div> |                 <span class="sr-only">{$_('action')}</span> | ||||||
|   {:then} |               </th> | ||||||
|     {#if current_teams.length === 0} |             </tr> | ||||||
|       <TeamsEmptyState /> |           </thead> | ||||||
|     {:else} |           <tbody class="divide-y divide-gray-200"> | ||||||
|       <input |             {#each current_teams as t} | ||||||
|         type="search" |               {#if Object.values(t) | ||||||
|         bind:value={searchvalue} |                 .toString() | ||||||
|         placeholder={$_('datatable.search')} |                 .toLowerCase() | ||||||
|         aria-label={$_('datatable.search')} |                 .includes(searchvalue)} | ||||||
|         class="gridjs-input gridjs-search-input mb-4" /> |                 <tr data-rowid="team_{t.id}"> | ||||||
|       <div class="h-12"> |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|         {#if current_teams.some((r) => r.is_selected === true)} |                     <input | ||||||
|           <div id="sponsoring:dropdown" class="relative inline-block"> |                       bind:checked={t.is_selected} | ||||||
|             <div> |                       type="checkbox" | ||||||
|               <button |                       class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" /> | ||||||
|                 on:click={() => { |                   </td> | ||||||
|                   sponsoring_contracts_download_open = !sponsoring_contracts_download_open; |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                 }} |                     <div class="flex items-center"> | ||||||
|                 type="button" |                       <div class="ml-4"> | ||||||
|                 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" |                         <div class="text-sm font-medium text-gray-900"> | ||||||
|                 id="options-menu" |                           {t.name} | ||||||
|                 aria-haspopup="true" |                         </div> | ||||||
|                 aria-expanded="true"> |                       </div> | ||||||
|                 {$_('generate-sponsoring-contracts')} |                     </div> | ||||||
|                 <svg |                   </td> | ||||||
|                   xmlns="http://www.w3.org/2000/svg" |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                   width="24" |                     <div class="flex items-center"> | ||||||
|                   height="24" |                       <div class="ml-4"> | ||||||
|                   viewBox="0 0 24 24" |                         <div class="text-sm font-medium text-gray-900"> | ||||||
|                   class="-mr-1 ml-2 h-5 w-5"><path |                           {#if t.parentGroup} | ||||||
|                     fill="none" |                             <a | ||||||
|                     d="M0 0h24v24H0z" /> |                               href="../orgs/{t.parentGroup.id}" | ||||||
|                   <path |                               class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{t.parentGroup.name}</a> | ||||||
|                     fill="currentColor" |                           {:else}{$_('no-organization-specified')}{/if} | ||||||
|                     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> |                         </div> | ||||||
|               </button> |                       </div> | ||||||
|             </div> |                     </div> | ||||||
|             {#if sponsoring_contracts_download_open} |                   </td> | ||||||
|               <div |                   <td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                 class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5" |                     <div class="flex items-center"> | ||||||
|                 id="sponsoring:dropdown:menu" |                       <div class="ml-4"> | ||||||
|                 on:click_outside={() => { |                         <div class="text-sm font-medium text-gray-900"> | ||||||
|                   sponsoring_contracts_download_open = false; |                           {#if t.contact} | ||||||
|                 }}> |                             <a | ||||||
|                 <div |                               href="../contacts/{t.contact.id}" | ||||||
|                   class="py-1" |                               class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{t.contact.firstname} | ||||||
|                   role="menu" |                               {t.contact.middlename || ''} | ||||||
|                   aria-orientation="vertical" |                               {t.contact.lastname}</a> | ||||||
|                   aria-labelledby="options-menu"> |                           {:else}{$_('no-contact-specified')}{/if} | ||||||
|                   <span |                         </div> | ||||||
|                     class="block w-full text-left px-4 py-2 text-sm text-gray-700">{$_('select-language')}</span> |                       </div> | ||||||
|                   <button |                     </div> | ||||||
|                     on:click={() => { |                   </td> | ||||||
|                       generateSponsoringContract('de'); |                   {#if active_deletes[t.id] === true} | ||||||
|                     }} |                     <td | ||||||
|                     type="submit" |                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|                     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 inline-flex" |                       <button | ||||||
|                     role="menuitem"> |                         on:click={() => { | ||||||
|                     {$_('german')} |                           active_deletes[t.id] = false; | ||||||
|                   </button> |                         }} | ||||||
|                   <button |                         tabindex="0" | ||||||
|                     on:click={() => { |                         class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">Cancel | ||||||
|                       generateSponsoringContract('en'); |                         Delete</button> | ||||||
|                     }} |                       <button | ||||||
|                     type="submit" |                         on:click={() => { | ||||||
|                     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 inline-flex" |                           RunnerTeamService.runnerTeamControllerRemove(t.id, false) | ||||||
|                     role="menuitem"> |                             .then((resp) => { | ||||||
|                     {$_('english')} |                               current_teams = current_teams.filter((obj) => obj.id !== t.id); | ||||||
|                   </button> |                               Toastify({ | ||||||
|                 </div> |                                 text: $_('organization-deleted'), | ||||||
|               </div> |                                 duration: 500, | ||||||
|             {/if} |                                 backgroundColor: | ||||||
|           </div> |                                   'linear-gradient(to right, #00b09b, #96c93d)', | ||||||
|         {/if} |                               }).showToast(); | ||||||
|       </div> |                             }) | ||||||
|       <div |                             .catch((err) => { | ||||||
|         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> |                               modal_open = true; | ||||||
|         <table class="divide-y divide-gray-200 w-full"> |                               delete_team = t; | ||||||
|           <thead class="bg-gray-50"> |                             }); | ||||||
|             <tr> |                         }} | ||||||
|               <th |                         tabindex="0" | ||||||
|                 scope="col" |                         class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button> | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |                     </td> | ||||||
|                 <span |                   {:else} | ||||||
|                   on:click={() => { |                     <td | ||||||
|                     const newstate = !current_teams.some((r) => r.is_selected === true); |                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | ||||||
|                     current_teams = current_teams.map((r) => { |                       <a | ||||||
|                       r.is_selected = newstate; |                         href="./{t.id}" | ||||||
|                       return r; |                         class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a> | ||||||
|                     }); |                       {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:DELETE')} | ||||||
|                   }} |                         <button | ||||||
|                   class="underline cursor-pointer select-none">{#if current_teams.some((r) => r.is_selected === true)} |                           on:click={() => { | ||||||
|                     {$_('deselect-all')} |                             active_deletes[t.id] = true; | ||||||
|                   {:else}{$_('select-all')}{/if} |                           }} | ||||||
|                 </span> |                           tabindex="0" | ||||||
|               </th> |                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button> | ||||||
|               <th |                       {/if} | ||||||
|                 scope="col" |                     </td> | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |                   {/if} | ||||||
|                 {$_('name')} |                 </tr> | ||||||
|               </th> |               {/if} | ||||||
|               <th |             {/each} | ||||||
|                 scope="col" |           </tbody> | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |         </table> | ||||||
|                 {$_('organization')} |       </div> | ||||||
|               </th> |     {/if} | ||||||
|               <th |   {:catch error} | ||||||
|                 scope="col" |     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |       <span class="inline-block align-middle mr-8"> | ||||||
|                 {$_('contact')} |         <b class="capitalize">{$_('general_promise_error')}</b> | ||||||
|               </th> |         {error} | ||||||
|               <th scope="col" class="relative px-6 py-3"> |       </span> | ||||||
|                 <span class="sr-only">{$_('action')}</span> |     </div> | ||||||
|               </th> |   {/await} | ||||||
|             </tr> | {/if} | ||||||
|           </thead> |  | ||||||
|           <tbody class="divide-y divide-gray-200"> |  | ||||||
|             {#each current_teams as t} |  | ||||||
|               {#if Object.values(t) |  | ||||||
|                 .toString() |  | ||||||
|                 .toLowerCase() |  | ||||||
|                 .includes(searchvalue)} |  | ||||||
|                 <tr data-rowid="team_{t.id}"> |  | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                     <input |  | ||||||
|                       bind:checked={t.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"> |  | ||||||
|                       <div class="ml-4"> |  | ||||||
|                         <div class="text-sm font-medium text-gray-900"> |  | ||||||
|                           {t.name} |  | ||||||
|                         </div> |  | ||||||
|                       </div> |  | ||||||
|                     </div> |  | ||||||
|                   </td> |  | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                     <div class="flex items-center"> |  | ||||||
|                       <div class="ml-4"> |  | ||||||
|                         <div class="text-sm font-medium text-gray-900"> |  | ||||||
|                           {#if t.parentGroup} |  | ||||||
|                             <a |  | ||||||
|                               href="../orgs/{t.parentGroup.id}" |  | ||||||
|                               class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{t.parentGroup.name}</a> |  | ||||||
|                           {:else}{$_('no-organization-specified')}{/if} |  | ||||||
|                         </div> |  | ||||||
|                       </div> |  | ||||||
|                     </div> |  | ||||||
|                   </td> |  | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                     <div class="flex items-center"> |  | ||||||
|                       <div class="ml-4"> |  | ||||||
|                         <div class="text-sm font-medium text-gray-900"> |  | ||||||
|                           {#if t.contact} |  | ||||||
|                             <a |  | ||||||
|                               href="../contacts/{t.contact.id}" |  | ||||||
|                               class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{t.contact.firstname} |  | ||||||
|                               {t.contact.middlename || ''} |  | ||||||
|                               {t.contact.lastname}</a> |  | ||||||
|                           {:else}{$_('no-contact-specified')}{/if} |  | ||||||
|                         </div> |  | ||||||
|                       </div> |  | ||||||
|                     </div> |  | ||||||
|                   </td> |  | ||||||
|                   {#if active_deletes[t.id] === true} |  | ||||||
|                     <td |  | ||||||
|                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> |  | ||||||
|                       <button |  | ||||||
|                         on:click={() => { |  | ||||||
|                           active_deletes[t.id] = false; |  | ||||||
|                         }} |  | ||||||
|                         tabindex="0" |  | ||||||
|                         class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">Cancel |  | ||||||
|                         Delete</button> |  | ||||||
|                       <button |  | ||||||
|                         on:click={() => { |  | ||||||
|                           RunnerTeamService.runnerTeamControllerRemove(t.id, false) |  | ||||||
|                             .then((resp) => { |  | ||||||
|                               current_teams = current_teams.filter((obj) => obj.id !== t.id); |  | ||||||
|                               Toastify({ |  | ||||||
|                                 text: $_('organization-deleted'), |  | ||||||
|                                 duration: 500, |  | ||||||
|                                 backgroundColor: |  | ||||||
|                                   'linear-gradient(to right, #00b09b, #96c93d)', |  | ||||||
|                               }).showToast(); |  | ||||||
|                             }) |  | ||||||
|                             .catch((err) => { |  | ||||||
|                               modal_open = true; |  | ||||||
|                               delete_team = t; |  | ||||||
|                             }); |  | ||||||
|                         }} |  | ||||||
|                         tabindex="0" |  | ||||||
|                         class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button> |  | ||||||
|                     </td> |  | ||||||
|                   {:else} |  | ||||||
|                     <td |  | ||||||
|                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> |  | ||||||
|                       <a |  | ||||||
|                         href="./{t.id}" |  | ||||||
|                         class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a> |  | ||||||
|                       {#if store.state.jwtinfo.userdetails.permissions.includes('TEAM:DELETE')} |  | ||||||
|                         <button |  | ||||||
|                           on:click={() => { |  | ||||||
|                             active_deletes[t.id] = true; |  | ||||||
|                           }} |  | ||||||
|                           tabindex="0" |  | ||||||
|                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button> |  | ||||||
|                       {/if} |  | ||||||
|                     </td> |  | ||||||
|                   {/if} |  | ||||||
|                 </tr> |  | ||||||
|               {/if} |  | ||||||
|             {/each} |  | ||||||
|           </tbody> |  | ||||||
|         </table> |  | ||||||
|       </div> |  | ||||||
|     {/if} |  | ||||||
|   {:catch error} |  | ||||||
|     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> |  | ||||||
|       <span class="inline-block align-middle mr-8"> |  | ||||||
|         <b class="capitalize">{$_('general_promise_error')}</b> |  | ||||||
|         {error} |  | ||||||
|       </span> |  | ||||||
|     </div> |  | ||||||
|   {/await} |  | ||||||
| {/if} |  | ||||||
|   | |||||||
| @@ -4,10 +4,13 @@ | |||||||
|     "about": "Über", |     "about": "Über", | ||||||
|     "action": "Aktionen", |     "action": "Aktionen", | ||||||
|     "active": "Aktiv", |     "active": "Aktiv", | ||||||
|  |     "add-card": "Karte erstellen", | ||||||
|     "add-donation": "Sponsoring erstellen", |     "add-donation": "Sponsoring erstellen", | ||||||
|     "add-donor": "Sponsor:in erstellen", |     "add-donor": "Sponsor:in erstellen", | ||||||
|     "add-scan": "Scan erstellen", |     "add-scan": "Scan erstellen", | ||||||
|  |     "add-the-first-scanstation": "Erstelle deine erste Scannerstation.", | ||||||
|     "add-user-group": "Neue Gruppe erstellen", |     "add-user-group": "Neue Gruppe erstellen", | ||||||
|  |     "add-your-first-card": "Erstelle deine erste Läuferkarte", | ||||||
|     "add-your-first-contact": "Erstelle den ersten Kontakt", |     "add-your-first-contact": "Erstelle den ersten Kontakt", | ||||||
|     "add-your-first-donor": "Erstelle die erste Sponsor:in", |     "add-your-first-donor": "Erstelle die erste Sponsor:in", | ||||||
|     "add-your-first-group": "Erstelle die erste Gruppe", |     "add-your-first-group": "Erstelle die erste Gruppe", | ||||||
| @@ -16,7 +19,9 @@ | |||||||
|     "add-your-first-team": "Erstelle das erste Team", |     "add-your-first-team": "Erstelle das erste Team", | ||||||
|     "add-your-first-track": "Erstelle den ersten Track (Laufstrecke).", |     "add-your-first-track": "Erstelle den ersten Track (Laufstrecke).", | ||||||
|     "add-your-first-user": "Erstelle die erste Benutzer:in", |     "add-your-first-user": "Erstelle die erste Benutzer:in", | ||||||
|     "add-your-fist-scan": "Füge deinene ersten Scan hinzu", |     "add-your-fist-donation": "Erstelle dein erstes Sponsoring", | ||||||
|  |     "add-your-fist-scan": "Füge deinen ersten Scan hinzu", | ||||||
|  |     "adding-card": "Karte wird erstellt", | ||||||
|     "adding-scan": "Scan wird hinzugefügt", |     "adding-scan": "Scan wird hinzugefügt", | ||||||
|     "address": "Adresse", |     "address": "Adresse", | ||||||
|     "address-is-required": "Du musst eine Adresse angeben", |     "address-is-required": "Du musst eine Adresse angeben", | ||||||
| @@ -25,6 +30,7 @@ | |||||||
|     "all-associated-donations-will-get-deleted-as-well": "Alle Sponsorings dieser Sponsor:in werden ebenfalls gelöscht", |     "all-associated-donations-will-get-deleted-as-well": "Alle Sponsorings dieser Sponsor:in werden ebenfalls gelöscht", | ||||||
|     "all-associated-runners-will-be-deleted-too": "Alle zugehörigen Läufer:innen werden auch gelöscht!", |     "all-associated-runners-will-be-deleted-too": "Alle zugehörigen Läufer:innen werden auch gelöscht!", | ||||||
|     "all-associated-teams-and-runners-will-be-deleted-too": "Alle assoziierten Teams und Läufer:innen werden auch gelöscht!", |     "all-associated-teams-and-runners-will-be-deleted-too": "Alle assoziierten Teams und Läufer:innen werden auch gelöscht!", | ||||||
|  |     "amount": "Anzahl", | ||||||
|     "amount-per-kilometer": "Betrag pro Kilometer", |     "amount-per-kilometer": "Betrag pro Kilometer", | ||||||
|     "apartment-suite-etc": "Apartment, Wohnung, etc.", |     "apartment-suite-etc": "Apartment, Wohnung, etc.", | ||||||
|     "application_name": "Lauf für Kaya! - Admin", |     "application_name": "Lauf für Kaya! - Admin", | ||||||
| @@ -40,10 +46,16 @@ | |||||||
|     "cancel-keep-organization": "Abbrechen und Organisation bearbeiten", |     "cancel-keep-organization": "Abbrechen und Organisation bearbeiten", | ||||||
|     "cancel-keep-team": "Abbrechen, Team behalten", |     "cancel-keep-team": "Abbrechen, Team behalten", | ||||||
|     "cannot-reset-your-password-directly": "Schade. \nWir können das Passwort leider nicht direkt zurücksetzen.\nBitte sende uns eine Mail in der du deine Identität bestätigst.", |     "cannot-reset-your-password-directly": "Schade. \nWir können das Passwort leider nicht direkt zurücksetzen.\nBitte sende uns eine Mail in der du deine Identität bestätigst.", | ||||||
|  |     "card-added": "Karte wurde hinzugefügt", | ||||||
|  |     "card-deleted": "Karte gelöscht", | ||||||
|  |     "card-updated": "Karte aktualisiert", | ||||||
|  |     "cards": "Läuferkarten", | ||||||
|     "change-your-password-here": "Hier kannst du dein Passwort ändern", |     "change-your-password-here": "Hier kannst du dein Passwort ändern", | ||||||
|     "changing-your-password": "Passwort wird geändert", |     "changing-your-password": "Passwort wird geändert", | ||||||
|     "city": "Stadt", |     "city": "Stadt", | ||||||
|  |     "click-to-copy-token-to-clipboard": "Klicke auf den Token, um ihn in deine Zwischenablage zu kopieren", | ||||||
|     "close": "Schließen", |     "close": "Schließen", | ||||||
|  |     "code": "Code", | ||||||
|     "configure-the-tracks-and-minimum-lap-times": "Bearbeite die Tracks und ihre minimale Rundenzeit", |     "configure-the-tracks-and-minimum-lap-times": "Bearbeite die Tracks und ihre minimale Rundenzeit", | ||||||
|     "confirm": "Bestätigen", |     "confirm": "Bestätigen", | ||||||
|     "confirm-delete": "Löschung Bestätigen", |     "confirm-delete": "Löschung Bestätigen", | ||||||
| @@ -60,10 +72,12 @@ | |||||||
|     "contact-is-not-a-member-in-any-group": "Kontakt gehört zu keiner Gruppe", |     "contact-is-not-a-member-in-any-group": "Kontakt gehört zu keiner Gruppe", | ||||||
|     "contacts": "Kontakte", |     "contacts": "Kontakte", | ||||||
|     "contacts-are-being-loaded": "Kontakte werden geladen ...", |     "contacts-are-being-loaded": "Kontakte werden geladen ...", | ||||||
|  |     "copied-token-to-clipboard": "Token wurde in die Zwischenablage kopiert", | ||||||
|     "count_organizations": "Organisationen (Anzahl)", |     "count_organizations": "Organisationen (Anzahl)", | ||||||
|     "count_teams": "Teams (Anzahl)", |     "count_teams": "Teams (Anzahl)", | ||||||
|     "create": "Erstellen", |     "create": "Erstellen", | ||||||
|     "create-a-new": "Erstelle eine neue", |     "create-a-new": "Erstelle eine neue", | ||||||
|  |     "create-a-new-card": "Neue Läuferkarte erstellen", | ||||||
|     "create-a-new-contact": "Kontakt erstellen", |     "create-a-new-contact": "Kontakt erstellen", | ||||||
|     "create-a-new-distance-donation": "Erstelle ein neues Sponsoring", |     "create-a-new-distance-donation": "Erstelle ein neues Sponsoring", | ||||||
|     "create-a-new-donor": "Neue Sponsor:in erstellen", |     "create-a-new-donor": "Neue Sponsor:in erstellen", | ||||||
| @@ -76,10 +90,14 @@ | |||||||
|     "create-a-new-track": "Neuen Track erstellen", |     "create-a-new-track": "Neuen Track erstellen", | ||||||
|     "create-a-new-user": "Neue Benutzer:in anlegen", |     "create-a-new-user": "Neue Benutzer:in anlegen", | ||||||
|     "create-a-new-user-group": "Erstelle eine neue Gruppe", |     "create-a-new-user-group": "Erstelle eine neue Gruppe", | ||||||
|  |     "create-bulk-blanco-cards": "Blankokarten erstellen", | ||||||
|  |     "create-bulk-cards": "Blankokarten erstellen", | ||||||
|     "create-organization": "Organisation erstellen", |     "create-organization": "Organisation erstellen", | ||||||
|     "create-team": "Team erstellen", |     "create-team": "Team erstellen", | ||||||
|     "create-track": "Track erstellen", |     "create-track": "Track erstellen", | ||||||
|     "create-user": "Benutzer anlegen", |     "create-user": "Benutzer anlegen", | ||||||
|  |     "created-blanco-cards": "Blankokarten wurden erstellt", | ||||||
|  |     "creating-blanco-cards": "Erstelle Blankokarten", | ||||||
|     "credits": "Credits", |     "credits": "Credits", | ||||||
|     "csv_import__class": "Klasse", |     "csv_import__class": "Klasse", | ||||||
|     "csv_import__firstname": "Vorname", |     "csv_import__firstname": "Vorname", | ||||||
| @@ -87,7 +105,7 @@ | |||||||
|     "csv_import__middlename": "Mittelname", |     "csv_import__middlename": "Mittelname", | ||||||
|     "csv_import__team": "Team", |     "csv_import__team": "Team", | ||||||
|     "danger-zone": "Gefahrenzone", |     "danger-zone": "Gefahrenzone", | ||||||
|     "dashboard-greeting": "Moin", |     "dashboard-greeting": "Hallo", | ||||||
|     "dashboard-title": "Dashboard", |     "dashboard-title": "Dashboard", | ||||||
|     "datatable": { |     "datatable": { | ||||||
|         "search": "🔍 Suche ...", |         "search": "🔍 Suche ...", | ||||||
| @@ -122,6 +140,7 @@ | |||||||
|     "description-optional": "Beschreibung (optional)", |     "description-optional": "Beschreibung (optional)", | ||||||
|     "deselect-all": "Alle abwählen", |     "deselect-all": "Alle abwählen", | ||||||
|     "details": "Details", |     "details": "Details", | ||||||
|  |     "disabled": "deaktiviert", | ||||||
|     "distance": "Distanz", |     "distance": "Distanz", | ||||||
|     "distance-donation": "Sponsoring", |     "distance-donation": "Sponsoring", | ||||||
|     "distance-in-km": "Distanz (in KM)", |     "distance-in-km": "Distanz (in KM)", | ||||||
| @@ -130,6 +149,7 @@ | |||||||
|     "do-you-want-to-delete-the-organization-delete_org-name": "Möchtest du die Organisation {orgname} löschen?", |     "do-you-want-to-delete-the-organization-delete_org-name": "Möchtest du die Organisation {orgname} löschen?", | ||||||
|     "do-you-want-to-delete-the-team-delete_team-name": "Möchtest du das Team {teamname} löschen?", |     "do-you-want-to-delete-the-team-delete_team-name": "Möchtest du das Team {teamname} löschen?", | ||||||
|     "do-you-want-to-delete-this-donor-with-all-related-donations": "Möchtest du diese Sponsor:in mit all ihren Sponsorings löschen?", |     "do-you-want-to-delete-this-donor-with-all-related-donations": "Möchtest du diese Sponsor:in mit all ihren Sponsorings löschen?", | ||||||
|  |     "documentation": "Dokumentation", | ||||||
|     "donation-amount": "Sponsoringbetrag", |     "donation-amount": "Sponsoringbetrag", | ||||||
|     "donation-amount-must-be-greater-that-0-00eur": "Der Sponsoringbetrag muss größer als 0.00€ sein.", |     "donation-amount-must-be-greater-that-0-00eur": "Der Sponsoringbetrag muss größer als 0.00€ sein.", | ||||||
|     "donations": "Sponsorings", |     "donations": "Sponsorings", | ||||||
| @@ -145,10 +165,14 @@ | |||||||
|     "dont-panic-were-resetting-it": "Keine Panik, wir setzen es zurück ✌", |     "dont-panic-were-resetting-it": "Keine Panik, wir setzen es zurück ✌", | ||||||
|     "e-mail-adress": "E-Mail-Adresse", |     "e-mail-adress": "E-Mail-Adresse", | ||||||
|     "edit": "Bearbeiten", |     "edit": "Bearbeiten", | ||||||
|  |     "edit-a-card": "Läuferkarte bearbeiten", | ||||||
|     "edit-permissions": "Berechtigungen bearbeiten", |     "edit-permissions": "Berechtigungen bearbeiten", | ||||||
|     "email_address_or_username": "E-Mail-Adresse/ Benutzername", |     "email_address_or_username": "E-Mail-Adresse/ Benutzername", | ||||||
|     "enabled": "aktiviert", |     "enabled": "aktiviert", | ||||||
|  |     "enabled_large": "Aktiviert", | ||||||
|     "english": "Englisch", |     "english": "Englisch", | ||||||
|  |     "error-during-import": "Fehler beim Importieren", | ||||||
|  |     "error-whyile-copying-to-clipboard": "Fehler beim Kopieren in die Zwischenablage", | ||||||
|     "error_on_login": "😢Fehler beim Login", |     "error_on_login": "😢Fehler beim Login", | ||||||
|     "erteilte": "Direkt erteilte", |     "erteilte": "Direkt erteilte", | ||||||
|     "everything-concerning-your-profile": "Alles zu deinem Profil", |     "everything-concerning-your-profile": "Alles zu deinem Profil", | ||||||
| @@ -163,6 +187,7 @@ | |||||||
|     "geerbte": "geerbte", |     "geerbte": "geerbte", | ||||||
|     "general-stats": "Allgemeine Statistiken", |     "general-stats": "Allgemeine Statistiken", | ||||||
|     "general_promise_error": "😢 Ein unbekannter Fehler ist aufgetreten", |     "general_promise_error": "😢 Ein unbekannter Fehler ist aufgetreten", | ||||||
|  |     "generate-runnercards": "Läuferkarten generieren", | ||||||
|     "generate-sponsoring-contract": "Sponsoringvertrag generieren", |     "generate-sponsoring-contract": "Sponsoringvertrag generieren", | ||||||
|     "generate-sponsoring-contracts": "Sponsoringverträge generieren", |     "generate-sponsoring-contracts": "Sponsoringverträge generieren", | ||||||
|     "generating-pdf": "Pdf wird generiert...", |     "generating-pdf": "Pdf wird generiert...", | ||||||
| @@ -181,6 +206,7 @@ | |||||||
|     "groups-are-being-loaded": "Gruppen werden geladen", |     "groups-are-being-loaded": "Gruppen werden geladen", | ||||||
|     "home": "Start", |     "home": "Start", | ||||||
|     "icon-image-credits": "Wir möchten uns außerdem für die verwendeten Icons und Bilder bedanken bei:", |     "icon-image-credits": "Wir möchten uns außerdem für die verwendeten Icons und Bilder bedanken bei:", | ||||||
|  |     "if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button": "Wenn du mehrere Blankokarten erstellen willst, nutze doch den \"Blankokarten erstellen\" Knopf.", | ||||||
|     "import-finished": "Import abgeschlossen", |     "import-finished": "Import abgeschlossen", | ||||||
|     "import-runners": "Läufer:innen importieren", |     "import-runners": "Läufer:innen importieren", | ||||||
|     "import__target-organization": "Ziel Organisation", |     "import__target-organization": "Ziel Organisation", | ||||||
| @@ -191,6 +217,7 @@ | |||||||
|     "internal-error": "Interner Fehler", |     "internal-error": "Interner Fehler", | ||||||
|     "invalid": "Ungültig", |     "invalid": "Ungültig", | ||||||
|     "invalid-mail-reset": "Das ist keine gültige E-Mail", |     "invalid-mail-reset": "Das ist keine gültige E-Mail", | ||||||
|  |     "just-enter-how-many-you-want-and-the-system-will-create-them": "Gebe einfach ein, wie viele Blankokarten das System erstellen soll.", | ||||||
|     "laeufer-hinzufuegen": "Läufer:in hinzufügen", |     "laeufer-hinzufuegen": "Läufer:in hinzufügen", | ||||||
|     "laeufer-importieren": "Läufer:innen importieren", |     "laeufer-importieren": "Läufer:innen importieren", | ||||||
|     "laptime": "Rundenzeit", |     "laptime": "Rundenzeit", | ||||||
| @@ -199,6 +226,7 @@ | |||||||
|     "lfk-is-os": "Das \"Lauf für Kaya!\" Frontend ist (wie alle anderen Projekte für den \"LfK!\" auch) ein OpenSource Projekt.", |     "lfk-is-os": "Das \"Lauf für Kaya!\" Frontend ist (wie alle anderen Projekte für den \"LfK!\" auch) ein OpenSource Projekt.", | ||||||
|     "license": "Lizenz", |     "license": "Lizenz", | ||||||
|     "licenses-are-being-loaded": "Lizenzen werden geladen...", |     "licenses-are-being-loaded": "Lizenzen werden geladen...", | ||||||
|  |     "loading-cards": "Läuferkarten werden geladen", | ||||||
|     "loading-contact-details": "Kontaktdaten werden geladen ...", |     "loading-contact-details": "Kontaktdaten werden geladen ...", | ||||||
|     "loading-donation-details": "Lade Sponsoringdetails", |     "loading-donation-details": "Lade Sponsoringdetails", | ||||||
|     "loading-donor-details": "Lade Details", |     "loading-donor-details": "Lade Details", | ||||||
| @@ -228,6 +256,7 @@ | |||||||
|     "no-organizations-found": "Keine Organisationen gefunden", |     "no-organizations-found": "Keine Organisationen gefunden", | ||||||
|     "no-runners-found": "Keine Läufer:innen gefunden", |     "no-runners-found": "Keine Läufer:innen gefunden", | ||||||
|     "no-tracks-added-yet": "Es wurden noch keine Tracks erstellt.", |     "no-tracks-added-yet": "Es wurden noch keine Tracks erstellt.", | ||||||
|  |     "non-blanko": "Keine/Blankokarte", | ||||||
|     "organization": "Organisation", |     "organization": "Organisation", | ||||||
|     "organization-added": "Organisation hinzugefügt", |     "organization-added": "Organisation hinzugefügt", | ||||||
|     "organization-deleted": "Organisation gelöscht", |     "organization-deleted": "Organisation gelöscht", | ||||||
| @@ -253,6 +282,7 @@ | |||||||
|     "permissions": "Berechtigungen", |     "permissions": "Berechtigungen", | ||||||
|     "permissions-updated": "Berechtigungen aktualisiert!", |     "permissions-updated": "Berechtigungen aktualisiert!", | ||||||
|     "phone": "Telefon", |     "phone": "Telefon", | ||||||
|  |     "please-copy-the-token-and-store-it-somewhere-save": "Bitte kopiere dir den Token und bewahre ihn gut auf.", | ||||||
|     "please-provide-a-password": "Bitte gebe ein Passwort an...", |     "please-provide-a-password": "Bitte gebe ein Passwort an...", | ||||||
|     "please-provide-the-nessecary-information-to-add-a-new-donor": "Bitte mach die Notwendigen Angaben, um eine neue Sponsor:in zu erstellen", |     "please-provide-the-nessecary-information-to-add-a-new-donor": "Bitte mach die Notwendigen Angaben, um eine neue Sponsor:in zu erstellen", | ||||||
|     "please-provide-the-nessecary-information-to-create-a-new-donation": "Bitte gebe alle für das Sponsoring notwendigen Daten an.", |     "please-provide-the-nessecary-information-to-create-a-new-donation": "Bitte gebe alle für das Sponsoring notwendigen Daten an.", | ||||||
| @@ -265,6 +295,7 @@ | |||||||
|     "please-provide-the-required-information-to-add-a-new-team": "Bitte gebe alle nötigen Informationen an, im das neue Team zu erstellen.", |     "please-provide-the-required-information-to-add-a-new-team": "Bitte gebe alle nötigen Informationen an, im das neue Team zu erstellen.", | ||||||
|     "please-provide-the-required-information-to-add-a-new-track": "Bitte die benötigten Informationen angeben.", |     "please-provide-the-required-information-to-add-a-new-track": "Bitte die benötigten Informationen angeben.", | ||||||
|     "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-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-request-a-new-reset-mail": "Bitte eine neue Passwortreset-Mail anfordern...", | ||||||
|     "privacy": "Datenschutz", |     "privacy": "Datenschutz", | ||||||
|     "privacy-loading": "Datenschutzerklärung lädt...", |     "privacy-loading": "Datenschutzerklärung lädt...", | ||||||
| @@ -294,6 +325,8 @@ | |||||||
|     "scans": "Scans", |     "scans": "Scans", | ||||||
|     "scans-are-being-loaded": "Scans werden geladen", |     "scans-are-being-loaded": "Scans werden geladen", | ||||||
|     "scanstation": "Scanner Station", |     "scanstation": "Scanner Station", | ||||||
|  |     "scanstation-added": "Station wurde erstellt", | ||||||
|  |     "scanstation-is-being-added": "Scannerstation wird angelegt...", | ||||||
|     "scanstations": "Scanner Stationen", |     "scanstations": "Scanner Stationen", | ||||||
|     "scanstations-are-being-loaded": "Scannerstationen werden geladen...", |     "scanstations-are-being-loaded": "Scannerstationen werden geladen...", | ||||||
|     "search-for-an-organization-by-name-or-id": "Suche eine Organisation (via Name oder Id)", |     "search-for-an-organization-by-name-or-id": "Suche eine Organisation (via Name oder Id)", | ||||||
| @@ -320,16 +353,21 @@ | |||||||
|     "teams-are-being-loaded": "Teams werden geladen ...", |     "teams-are-being-loaded": "Teams werden geladen ...", | ||||||
|     "the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number": "Die angegebene Telefonnummer ist nicht korrekt. <br /> Bitte gebe eine Telefonnummer im internationalen Format an...", |     "the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number": "Die angegebene Telefonnummer ist nicht korrekt. <br /> Bitte gebe eine Telefonnummer im internationalen Format an...", | ||||||
|     "the-scans-distance-must-be-greater-than-0m": "Die Distanz muss größer als 0m sein.", |     "the-scans-distance-must-be-greater-than-0m": "Die Distanz muss größer als 0m sein.", | ||||||
|  |     "the-scanstations-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again": "Der Scannerstation Token wird nur einmal angezeigt - du kannst ihn nicht ändern oder ihn dir nochmal anzeigen lassen!", | ||||||
|  |     "there-are-no-cards-yet": "Es gibt noch keine Läuferkarten.", | ||||||
|     "there-are-no-contacts-added-yet": "Es wurden noch keine Kontakte hinzugefügt.", |     "there-are-no-contacts-added-yet": "Es wurden noch keine Kontakte hinzugefügt.", | ||||||
|  |     "there-are-no-donations-yet": "Es gibt noch keine Sponsorings", | ||||||
|     "there-are-no-donors-yet": "Es gibt noch keine Sponsor:innen", |     "there-are-no-donors-yet": "Es gibt noch keine Sponsor:innen", | ||||||
|     "there-are-no-groups-yet": "Es gibt noch keine Gruppen", |     "there-are-no-groups-yet": "Es gibt noch keine Gruppen", | ||||||
|     "there-are-no-organizations-added-yet": "Es wurden noch keine Organisationen hinzugefügt.", |     "there-are-no-organizations-added-yet": "Es wurden noch keine Organisationen hinzugefügt.", | ||||||
|     "there-are-no-runners-added-yet": "Es wurden noch keine Läufer:innen hinzugefügt.", |     "there-are-no-runners-added-yet": "Es wurden noch keine Läufer:innen hinzugefügt.", | ||||||
|     "there-are-no-scans-yet": "Es gibt noch keine scans", |     "there-are-no-scans-yet": "Es gibt noch keine Scans", | ||||||
|     "there-are-no-teams-added-yet": "Es wurden noch keine Teams hinzugefügt.", |     "there-are-no-teams-added-yet": "Es wurden noch keine Teams hinzugefügt.", | ||||||
|     "there-are-no-users-added-yet": "Es wurden noch keine Benutzer hinzugefügt.", |     "there-are-no-users-added-yet": "Es wurden noch keine Benutzer hinzugefügt.", | ||||||
|  |     "this-card-is": "Diese Karte ist", | ||||||
|     "this-might-take-a-moment": "Das könnte einen kleinen Moment dauern", |     "this-might-take-a-moment": "Das könnte einen kleinen Moment dauern", | ||||||
|     "this-scanstation-is": "Diese Station ist", |     "this-scanstation-is": "Diese Station ist", | ||||||
|  |     "token": "Token", | ||||||
|     "total-distance": "gelaufene Strecke", |     "total-distance": "gelaufene Strecke", | ||||||
|     "total-donation-amount": "Gesamtbetrag", |     "total-donation-amount": "Gesamtbetrag", | ||||||
|     "total-donations": "Spendensumme", |     "total-donations": "Spendensumme", | ||||||
| @@ -349,6 +387,7 @@ | |||||||
|     "updated-organization": "Organisation wurde aktualisiert", |     "updated-organization": "Organisation wurde aktualisiert", | ||||||
|     "updated-scan": "Scan wurde aktualisiert", |     "updated-scan": "Scan wurde aktualisiert", | ||||||
|     "updateing-group": "Gruppe wird aktualisiert...", |     "updateing-group": "Gruppe wird aktualisiert...", | ||||||
|  |     "updating-card": "Karte wird aktualisiert", | ||||||
|     "updating-organization": "Organisation wird aktualisiert", |     "updating-organization": "Organisation wird aktualisiert", | ||||||
|     "updating-permissions": "Berechtigungen werden aktualisiert...", |     "updating-permissions": "Berechtigungen werden aktualisiert...", | ||||||
|     "updating-runner": "Läufer:in wird aktualisiert.", |     "updating-runner": "Läufer:in wird aktualisiert.", | ||||||
| @@ -370,6 +409,9 @@ | |||||||
|     "yes-i-copied-the-token": "Ja, ich habe den Token kopiert", |     "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-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-now-use-your-new-password-to-log-in-to-your-account": "Du kannst dich jetzt mit deinem neuen Passwort anmelden! 🎉", |     "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", | ||||||
|     "you-have-to-provide-an-organization": "Du musst eine Organisation angeben", |     "you-have-to-provide-an-organization": "Du musst eine Organisation angeben", | ||||||
|  |     "you-must-create-at-least-one-card-or-cancel": "Du musst mindestens eine Blankokarte erstellen (oder abbrechen).", | ||||||
|     "zip-postal-code": "Postleitzahl" |     "zip-postal-code": "Postleitzahl" | ||||||
| } | } | ||||||
| @@ -4,10 +4,13 @@ | |||||||
|     "about": "About", |     "about": "About", | ||||||
|     "action": "Action", |     "action": "Action", | ||||||
|     "active": "Active", |     "active": "Active", | ||||||
|  |     "add-card": "Add Card", | ||||||
|     "add-donation": "Add donation", |     "add-donation": "Add donation", | ||||||
|     "add-donor": "add donor", |     "add-donor": "add donor", | ||||||
|     "add-scan": "Add scan", |     "add-scan": "Add scan", | ||||||
|  |     "add-the-first-scanstation": "Add your first scanstation.", | ||||||
|     "add-user-group": "Add User Group", |     "add-user-group": "Add User Group", | ||||||
|  |     "add-your-first-card": "Add your first card", | ||||||
|     "add-your-first-contact": "Add your first contact", |     "add-your-first-contact": "Add your first contact", | ||||||
|     "add-your-first-donor": "add your first donor", |     "add-your-first-donor": "add your first donor", | ||||||
|     "add-your-first-group": "Add your first group", |     "add-your-first-group": "Add your first group", | ||||||
| @@ -16,7 +19,9 @@ | |||||||
|     "add-your-first-team": "Add your first team", |     "add-your-first-team": "Add your first team", | ||||||
|     "add-your-first-track": "Add your first track.", |     "add-your-first-track": "Add your first track.", | ||||||
|     "add-your-first-user": "Add your first user", |     "add-your-first-user": "Add your first user", | ||||||
|  |     "add-your-fist-donation": "Add your fist donation", | ||||||
|     "add-your-fist-scan": "Add your fist scan", |     "add-your-fist-scan": "Add your fist scan", | ||||||
|  |     "adding-card": "Adding Card", | ||||||
|     "adding-scan": "Adding Scan", |     "adding-scan": "Adding Scan", | ||||||
|     "address": "Address", |     "address": "Address", | ||||||
|     "address-is-required": "Address is required", |     "address-is-required": "Address is required", | ||||||
| @@ -25,6 +30,7 @@ | |||||||
|     "all-associated-donations-will-get-deleted-as-well": "All associated donations will get deleted as well", |     "all-associated-donations-will-get-deleted-as-well": "All associated donations will get deleted as well", | ||||||
|     "all-associated-runners-will-be-deleted-too": "All associated runners will be deleted too!", |     "all-associated-runners-will-be-deleted-too": "All associated runners will be deleted too!", | ||||||
|     "all-associated-teams-and-runners-will-be-deleted-too": "All associated teams and runners will be deleted too!", |     "all-associated-teams-and-runners-will-be-deleted-too": "All associated teams and runners will be deleted too!", | ||||||
|  |     "amount": "Amount", | ||||||
|     "amount-per-kilometer": "Amount per kilometer", |     "amount-per-kilometer": "Amount per kilometer", | ||||||
|     "apartment-suite-etc": "Apartment, suite, etc.", |     "apartment-suite-etc": "Apartment, suite, etc.", | ||||||
|     "application_name": "Lauf für Kaya! - Admin", |     "application_name": "Lauf für Kaya! - Admin", | ||||||
| @@ -40,10 +46,16 @@ | |||||||
|     "cancel-keep-organization": "Cancel, keep organization", |     "cancel-keep-organization": "Cancel, keep organization", | ||||||
|     "cancel-keep-team": "Cancel, keep team", |     "cancel-keep-team": "Cancel, keep team", | ||||||
|     "cannot-reset-your-password-directly": "Bummer. We unfortunately cannot reset your password directly. Please send us a mail and confirm your identity", |     "cannot-reset-your-password-directly": "Bummer. We unfortunately cannot reset your password directly. Please send us a mail and confirm your identity", | ||||||
|  |     "card-added": "Card added", | ||||||
|  |     "card-deleted": "Card deleted", | ||||||
|  |     "card-updated": "Card updated", | ||||||
|  |     "cards": "Cards", | ||||||
|     "change-your-password-here": "Change your password here", |     "change-your-password-here": "Change your password here", | ||||||
|     "changing-your-password": "Changing your password", |     "changing-your-password": "Changing your password", | ||||||
|     "city": "City", |     "city": "City", | ||||||
|  |     "click-to-copy-token-to-clipboard": "Click to copy the token to your clipboard", | ||||||
|     "close": "Close", |     "close": "Close", | ||||||
|  |     "code": "Code", | ||||||
|     "configure-the-tracks-and-minimum-lap-times": "configure the tracks & minimum lap times", |     "configure-the-tracks-and-minimum-lap-times": "configure the tracks & minimum lap times", | ||||||
|     "confirm": "Confirm", |     "confirm": "Confirm", | ||||||
|     "confirm-delete": "Confirm Delete", |     "confirm-delete": "Confirm Delete", | ||||||
| @@ -60,10 +72,12 @@ | |||||||
|     "contact-is-not-a-member-in-any-group": "Contact is not a member in any group", |     "contact-is-not-a-member-in-any-group": "Contact is not a member in any group", | ||||||
|     "contacts": "Contacts", |     "contacts": "Contacts", | ||||||
|     "contacts-are-being-loaded": "contacts are being loaded...", |     "contacts-are-being-loaded": "contacts are being loaded...", | ||||||
|  |     "copied-token-to-clipboard": "Copied token to clipboard", | ||||||
|     "count_organizations": "# Organizations", |     "count_organizations": "# Organizations", | ||||||
|     "count_teams": "# Teams", |     "count_teams": "# Teams", | ||||||
|     "create": "Create", |     "create": "Create", | ||||||
|     "create-a-new": "Create a new", |     "create-a-new": "Create a new", | ||||||
|  |     "create-a-new-card": "Create a new card", | ||||||
|     "create-a-new-contact": "Create a new contact", |     "create-a-new-contact": "Create a new contact", | ||||||
|     "create-a-new-distance-donation": "Create a new distance donation", |     "create-a-new-distance-donation": "Create a new distance donation", | ||||||
|     "create-a-new-donor": "Create a new donor", |     "create-a-new-donor": "Create a new donor", | ||||||
| @@ -76,10 +90,14 @@ | |||||||
|     "create-a-new-track": "Create a new Track", |     "create-a-new-track": "Create a new Track", | ||||||
|     "create-a-new-user": "Create a new User", |     "create-a-new-user": "Create a new User", | ||||||
|     "create-a-new-user-group": "Create a new user group", |     "create-a-new-user-group": "Create a new user group", | ||||||
|  |     "create-bulk-blanco-cards": "Create bulk blanco cards", | ||||||
|  |     "create-bulk-cards": "Add blanco cards", | ||||||
|     "create-organization": "Create Organization", |     "create-organization": "Create Organization", | ||||||
|     "create-team": "Create Team", |     "create-team": "Create Team", | ||||||
|     "create-track": "Create Track", |     "create-track": "Create Track", | ||||||
|     "create-user": "Create User", |     "create-user": "Create User", | ||||||
|  |     "created-blanco-cards": "Created blanco cards", | ||||||
|  |     "creating-blanco-cards": "Creating blanco cards", | ||||||
|     "credits": "Credits", |     "credits": "Credits", | ||||||
|     "csv_import__class": "Class", |     "csv_import__class": "Class", | ||||||
|     "csv_import__firstname": "Firstname", |     "csv_import__firstname": "Firstname", | ||||||
| @@ -87,7 +105,7 @@ | |||||||
|     "csv_import__middlename": "Middlename", |     "csv_import__middlename": "Middlename", | ||||||
|     "csv_import__team": "Team", |     "csv_import__team": "Team", | ||||||
|     "danger-zone": "Danger zone", |     "danger-zone": "Danger zone", | ||||||
|     "dashboard-greeting": "hello there", |     "dashboard-greeting": "Hello", | ||||||
|     "dashboard-title": "Dashboard", |     "dashboard-title": "Dashboard", | ||||||
|     "datatable": { |     "datatable": { | ||||||
|         "search": "🔍 Search...", |         "search": "🔍 Search...", | ||||||
| @@ -122,6 +140,7 @@ | |||||||
|     "description-optional": "Description (optional)", |     "description-optional": "Description (optional)", | ||||||
|     "deselect-all": "deselect all", |     "deselect-all": "deselect all", | ||||||
|     "details": "Details", |     "details": "Details", | ||||||
|  |     "disabled": "disabled", | ||||||
|     "distance": "Distance", |     "distance": "Distance", | ||||||
|     "distance-donation": "distance donation", |     "distance-donation": "distance donation", | ||||||
|     "distance-in-km": "Distance in km", |     "distance-in-km": "Distance in km", | ||||||
| @@ -130,6 +149,7 @@ | |||||||
|     "do-you-want-to-delete-the-organization-delete_org-name": "Do you want to delete the organization {orgname}?", |     "do-you-want-to-delete-the-organization-delete_org-name": "Do you want to delete the organization {orgname}?", | ||||||
|     "do-you-want-to-delete-the-team-delete_team-name": "Do you want to delete the team {teamname}?", |     "do-you-want-to-delete-the-team-delete_team-name": "Do you want to delete the team {teamname}?", | ||||||
|     "do-you-want-to-delete-this-donor-with-all-related-donations": "Do you want to delete this donor with all related donations", |     "do-you-want-to-delete-this-donor-with-all-related-donations": "Do you want to delete this donor with all related donations", | ||||||
|  |     "documentation": "Documentation", | ||||||
|     "donation-amount": "Donation amount", |     "donation-amount": "Donation amount", | ||||||
|     "donation-amount-must-be-greater-that-0-00eur": "Donation amount must be greater that 0.00€", |     "donation-amount-must-be-greater-that-0-00eur": "Donation amount must be greater that 0.00€", | ||||||
|     "donations": "Donations", |     "donations": "Donations", | ||||||
| @@ -145,10 +165,14 @@ | |||||||
|     "dont-panic-were-resetting-it": "Don't panic, we're resetting it ✌", |     "dont-panic-were-resetting-it": "Don't panic, we're resetting it ✌", | ||||||
|     "e-mail-adress": "E-Mail Adress", |     "e-mail-adress": "E-Mail Adress", | ||||||
|     "edit": "Edit", |     "edit": "Edit", | ||||||
|  |     "edit-a-card": "Edit a card", | ||||||
|     "edit-permissions": "edit permissions", |     "edit-permissions": "edit permissions", | ||||||
|     "email_address_or_username": "Email / username", |     "email_address_or_username": "Email / username", | ||||||
|     "enabled": "enabled", |     "enabled": "enabled", | ||||||
|  |     "enabled_large": "Enabled", | ||||||
|     "english": "English", |     "english": "English", | ||||||
|  |     "error-during-import": "Error during import", | ||||||
|  |     "error-whyile-copying-to-clipboard": "Error while copying to clipboard", | ||||||
|     "error_on_login": "Error on login", |     "error_on_login": "Error on login", | ||||||
|     "erteilte": "Directly granted", |     "erteilte": "Directly granted", | ||||||
|     "everything-concerning-your-profile": "Everything concerning your profile", |     "everything-concerning-your-profile": "Everything concerning your profile", | ||||||
| @@ -163,6 +187,7 @@ | |||||||
|     "geerbte": "inherited", |     "geerbte": "inherited", | ||||||
|     "general-stats": "General Stats", |     "general-stats": "General Stats", | ||||||
|     "general_promise_error": "😢 Error", |     "general_promise_error": "😢 Error", | ||||||
|  |     "generate-runnercards": "Generate Runnercards", | ||||||
|     "generate-sponsoring-contract": "generate sponsoring contract", |     "generate-sponsoring-contract": "generate sponsoring contract", | ||||||
|     "generate-sponsoring-contracts": "generate sponsoring contracts", |     "generate-sponsoring-contracts": "generate sponsoring contracts", | ||||||
|     "generating-pdf": "generating PDF...", |     "generating-pdf": "generating PDF...", | ||||||
| @@ -181,6 +206,7 @@ | |||||||
|     "groups-are-being-loaded": "Groups are being loaded", |     "groups-are-being-loaded": "Groups are being loaded", | ||||||
|     "home": "Home", |     "home": "Home", | ||||||
|     "icon-image-credits": "We also want to thank these projects for illustrations and icons:", |     "icon-image-credits": "We also want to thank these projects for illustrations and icons:", | ||||||
|  |     "if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button": "If you want to create multiple blanco cards: Try the 'Add blanco cards' button.", | ||||||
|     "import-finished": "Import finished", |     "import-finished": "Import finished", | ||||||
|     "import-runners": "Import runners", |     "import-runners": "Import runners", | ||||||
|     "import__target-organization": "Target Organization", |     "import__target-organization": "Target Organization", | ||||||
| @@ -191,6 +217,7 @@ | |||||||
|     "internal-error": "Internal Error", |     "internal-error": "Internal Error", | ||||||
|     "invalid": "Invalid", |     "invalid": "Invalid", | ||||||
|     "invalid-mail-reset": "the provided email is invalid", |     "invalid-mail-reset": "the provided email is invalid", | ||||||
|  |     "just-enter-how-many-you-want-and-the-system-will-create-them": "Just enter how many you want and the system will create them", | ||||||
|     "laeufer-hinzufuegen": "Add runner", |     "laeufer-hinzufuegen": "Add runner", | ||||||
|     "laeufer-importieren": "Läufer importieren", |     "laeufer-importieren": "Läufer importieren", | ||||||
|     "laptime": "Laptime", |     "laptime": "Laptime", | ||||||
| @@ -199,6 +226,7 @@ | |||||||
|     "lfk-is-os": "The \"Lauf für Kaya!\" Frontend is (like all other projects for the \"LfK!\" Also) an open source project.", |     "lfk-is-os": "The \"Lauf für Kaya!\" Frontend is (like all other projects for the \"LfK!\" Also) an open source project.", | ||||||
|     "license": "License", |     "license": "License", | ||||||
|     "licenses-are-being-loaded": "Licenses are being loaded...", |     "licenses-are-being-loaded": "Licenses are being loaded...", | ||||||
|  |     "loading-cards": "Loading cards", | ||||||
|     "loading-contact-details": "Loading contact details...", |     "loading-contact-details": "Loading contact details...", | ||||||
|     "loading-donation-details": "Loading donation details", |     "loading-donation-details": "Loading donation details", | ||||||
|     "loading-donor-details": "Loading donor details", |     "loading-donor-details": "Loading donor details", | ||||||
| @@ -228,6 +256,7 @@ | |||||||
|     "no-organizations-found": "No organizations found", |     "no-organizations-found": "No organizations found", | ||||||
|     "no-runners-found": "No runners found", |     "no-runners-found": "No runners found", | ||||||
|     "no-tracks-added-yet": "there are no tracks added yet.", |     "no-tracks-added-yet": "there are no tracks added yet.", | ||||||
|  |     "non-blanko": "Non/Blanko", | ||||||
|     "organization": "Organization", |     "organization": "Organization", | ||||||
|     "organization-added": "Organization added", |     "organization-added": "Organization added", | ||||||
|     "organization-deleted": "Organization deleted", |     "organization-deleted": "Organization deleted", | ||||||
| @@ -253,6 +282,7 @@ | |||||||
|     "permissions": "Permissions", |     "permissions": "Permissions", | ||||||
|     "permissions-updated": "Permissions updated!", |     "permissions-updated": "Permissions updated!", | ||||||
|     "phone": "Phone", |     "phone": "Phone", | ||||||
|  |     "please-copy-the-token-and-store-it-somewhere-save": "Please copy the token and store it somewhere safe.", | ||||||
|     "please-provide-a-password": "Please provide a password...", |     "please-provide-a-password": "Please provide a password...", | ||||||
|     "please-provide-the-nessecary-information-to-add-a-new-donor": "Please provide the nessecary information to add a new donor", |     "please-provide-the-nessecary-information-to-add-a-new-donor": "Please provide the nessecary information to add a new donor", | ||||||
|     "please-provide-the-nessecary-information-to-create-a-new-donation": "Please provide the nessecary information to create a new donation", |     "please-provide-the-nessecary-information-to-create-a-new-donation": "Please provide the nessecary information to create a new donation", | ||||||
| @@ -265,6 +295,7 @@ | |||||||
|     "please-provide-the-required-information-to-add-a-new-team": "Please provide the required information to add a new team.", |     "please-provide-the-required-information-to-add-a-new-team": "Please provide the required information to add a new team.", | ||||||
|     "please-provide-the-required-information-to-add-a-new-track": "Please provide the required information to add a new track.", |     "please-provide-the-required-information-to-add-a-new-track": "Please provide the required information to add a new track.", | ||||||
|     "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-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-request-a-new-reset-mail": "Please request a new reset mail...", | ||||||
|     "privacy": "Privacy", |     "privacy": "Privacy", | ||||||
|     "privacy-loading": "Privacy loading...", |     "privacy-loading": "Privacy loading...", | ||||||
| @@ -294,6 +325,8 @@ | |||||||
|     "scans": "Scans", |     "scans": "Scans", | ||||||
|     "scans-are-being-loaded": "Scans are being loaded", |     "scans-are-being-loaded": "Scans are being loaded", | ||||||
|     "scanstation": "Scanstation", |     "scanstation": "Scanstation", | ||||||
|  |     "scanstation-added": "Scanstation added", | ||||||
|  |     "scanstation-is-being-added": "Adding scanstation...", | ||||||
|     "scanstations": "Scanstations", |     "scanstations": "Scanstations", | ||||||
|     "scanstations-are-being-loaded": "Loading scanstations...", |     "scanstations-are-being-loaded": "Loading scanstations...", | ||||||
|     "search-for-an-organization-by-name-or-id": "Search for an organization (by name or id)", |     "search-for-an-organization-by-name-or-id": "Search for an organization (by name or id)", | ||||||
| @@ -320,7 +353,10 @@ | |||||||
|     "teams-are-being-loaded": "teams are being loaded...", |     "teams-are-being-loaded": "teams are being loaded...", | ||||||
|     "the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number": "the provided phone number is invalid.<br />please enter a valid international number...", |     "the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number": "the provided phone number is invalid.<br />please enter a valid international number...", | ||||||
|     "the-scans-distance-must-be-greater-than-0m": "The scan's distance must be greater than 0m", |     "the-scans-distance-must-be-greater-than-0m": "The scan's distance must be greater than 0m", | ||||||
|  |     "the-scanstations-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again": "The scanstation api token will only get displayed once - you won't be able to change or view it again!", | ||||||
|  |     "there-are-no-cards-yet": "There are no cards yet.", | ||||||
|     "there-are-no-contacts-added-yet": "There are no contacts added yet.", |     "there-are-no-contacts-added-yet": "There are no contacts added yet.", | ||||||
|  |     "there-are-no-donations-yet": "There are no donations yet", | ||||||
|     "there-are-no-donors-yet": "There are no donors yet", |     "there-are-no-donors-yet": "There are no donors yet", | ||||||
|     "there-are-no-groups-yet": "There are no groups yet", |     "there-are-no-groups-yet": "There are no groups yet", | ||||||
|     "there-are-no-organizations-added-yet": "There are no organizations added yet.", |     "there-are-no-organizations-added-yet": "There are no organizations added yet.", | ||||||
| @@ -328,8 +364,10 @@ | |||||||
|     "there-are-no-scans-yet": "There are no scans yet", |     "there-are-no-scans-yet": "There are no scans yet", | ||||||
|     "there-are-no-teams-added-yet": "There are no teams added yet.", |     "there-are-no-teams-added-yet": "There are no teams added yet.", | ||||||
|     "there-are-no-users-added-yet": "There are no users added yet.", |     "there-are-no-users-added-yet": "There are no users added yet.", | ||||||
|  |     "this-card-is": "This card is", | ||||||
|     "this-might-take-a-moment": "This might take a moment 👀", |     "this-might-take-a-moment": "This might take a moment 👀", | ||||||
|     "this-scanstation-is": "This scanstation is", |     "this-scanstation-is": "This scanstation is", | ||||||
|  |     "token": "Token", | ||||||
|     "total-distance": "total distance", |     "total-distance": "total distance", | ||||||
|     "total-donation-amount": "total donation amount", |     "total-donation-amount": "total donation amount", | ||||||
|     "total-donations": "total donations", |     "total-donations": "total donations", | ||||||
| @@ -343,12 +381,14 @@ | |||||||
|     "track-name": "Track name", |     "track-name": "Track name", | ||||||
|     "track-name-must-not-be-empty": "Track name must not be empty", |     "track-name-must-not-be-empty": "Track name must not be empty", | ||||||
|     "tracks": "Tracks", |     "tracks": "Tracks", | ||||||
|  |     "update-card": "Update Card", | ||||||
|     "update-password": "Update password", |     "update-password": "Update password", | ||||||
|     "updated-contact": "Updated contact!", |     "updated-contact": "Updated contact!", | ||||||
|     "updated-donor": "updated donor", |     "updated-donor": "updated donor", | ||||||
|     "updated-organization": "updated organization", |     "updated-organization": "updated organization", | ||||||
|     "updated-scan": "updated scan", |     "updated-scan": "updated scan", | ||||||
|     "updateing-group": "updateing group...", |     "updateing-group": "updateing group...", | ||||||
|  |     "updating-card": "Updating card", | ||||||
|     "updating-organization": "updating organization", |     "updating-organization": "updating organization", | ||||||
|     "updating-permissions": "updating permissions...", |     "updating-permissions": "updating permissions...", | ||||||
|     "updating-runner": "Updating runner...", |     "updating-runner": "Updating runner...", | ||||||
| @@ -370,6 +410,9 @@ | |||||||
|     "yes-i-copied-the-token": "Yes, I copied the token", |     "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-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-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-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", | ||||||
|     "you-have-to-provide-an-organization": "You have to provide an organization", |     "you-have-to-provide-an-organization": "You have to provide an organization", | ||||||
|  |     "you-must-create-at-least-one-card-or-cancel": "You must create at least one card (or cancel).", | ||||||
|     "zip-postal-code": "ZIP/ postal code" |     "zip-postal-code": "ZIP/ postal code" | ||||||
| } | } | ||||||
		Reference in New Issue
	
	Block a user