Compare commits
	
		
			170 Commits
		
	
	
		
			1.4.1
			...
			feature/ca
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 062daa6a0c | |||
| cfc3c44f9f | |||
| d2bc780656 | |||
| dc5ea5240c | |||
| fcadedaa30 | |||
| 2a4fe2b28f | |||
| 87df34bb56 | |||
| 9c3b742a98 | |||
| 68bf3717f9 | |||
| f88c6e0dba | |||
| 12050cdda9 | |||
| 01e77a97f3 | |||
| 10824b5d9b | |||
| d9870e03bc | |||
| 785b9e0b60 | |||
| fce2bc645e | |||
| 991716a7f5 | |||
| aa720f2460 | |||
| ac4ef8fb6d | |||
| eae0afda23 | |||
| 5291f8a4d1 | |||
| e2d7de1e9e | |||
| d7c9c27ec7 | |||
| 153b1b3c2b | |||
| ec63c7c1c5 | |||
| 05c2535698 | |||
| e261d5e345 | |||
| c00497d776 | |||
| 766eeab49f | |||
| 3c9b404234 | |||
| 9c56b3883e | |||
| 3d506db975 | |||
| d7e84a79a8 | |||
| 102471eaaa | |||
| 90b0fec236 | |||
| 4883e179e7 | |||
| 13c6e96292 | |||
| f547c0cc81 | |||
| fbe38eede9 | |||
| 22551c379f | |||
| a102af5a78 | |||
| e9dffcea83 | |||
| b9563d75dd | |||
| 3a569422ad | |||
| 0ee43f80a6 | |||
| f4542adf3b | |||
| 9f0623d194 | |||
| 5bab95a942 | |||
| 831f36946d | |||
| a4fbabaf9a | |||
| 04897c7d2e | |||
| b7e6fdaeac | |||
| 481f6b686e | |||
| e7a69ebdca | |||
| 194c3c4886 | |||
| f5a46aa203 | |||
| 443371e2fd | |||
| d7ab9247cd | |||
| a2cd54fba4 | |||
| 9048f3df77 | |||
| fecf3b59a3 | |||
| 18a4623e71 | |||
| 968a7ccc0e | |||
| 6249502a88 | |||
| 8a78034079 | |||
| 7633b7b056 | |||
| b8e6b24bf3 | |||
| 97b7ca931f | |||
| 48dd9acde5 | |||
| 5147a20b3c | |||
| bb2319a78d | |||
| 7c10d95c1c | |||
| f734d1e3f6 | |||
| e567bb35c3 | |||
| 3ec18a6964 | |||
| 847fa288f1 | |||
| 824ecfab2e | |||
| 5f5d8277b9 | |||
| 0a6cf619b0 | |||
| 050a146ae0 | |||
| 1bc53146b9 | |||
| e82350df4a | |||
| 3d3ce2918b | |||
| 79e6a4212d | |||
| 37cdbba0a3 | |||
| c37fb98bed | |||
| 975f145444 | |||
| 391186d01f | |||
| ae056cd88c | |||
| 7f989b206b | |||
| 65ce02e777 | |||
| 878d9714cb | |||
| f99b7f4bb8 | |||
| e23098410c | |||
| 04494d2a2a | |||
| e2d6fbb513 | |||
| 477c650f3f | |||
| fc15c68cba | |||
| 32b5f5420b | |||
| ee87f82799 | |||
| 7c08f522aa | |||
| e211554579 | |||
| 7ba890dfd7 | |||
| 68b4309164 | |||
| d803f3d490 | |||
| 5468766d87 | |||
| e967d8d20c | |||
| ad4db882f0 | |||
| 84aa846b87 | |||
| 3532968b33 | |||
| 6bb49db4ee | |||
| 38fb111f7a | |||
| a50447f457 | |||
| b1a2044631 | |||
| c883920caa | |||
| 21453ef272 | |||
| 10182433f8 | |||
| b338f33a63 | |||
| cb82200481 | |||
| 9abf74d6d2 | |||
| 50e81a6cb5 | |||
| 8fae1fb6b3 | |||
| 372fa110ec | |||
| 35bec9fe58 | |||
| 93d67bdba9 | |||
| a5e72a18e3 | |||
| 91d2f46b93 | |||
| c60bae4533 | |||
| 43ac878d44 | |||
| ceabd06a43 | |||
| 9bfc0c5338 | |||
| fb8206ff13 | |||
| dceb0ef461 | |||
| 88bc1982ca | |||
| e741a9d7e7 | |||
| 65f1d22205 | |||
| d867c08aba | |||
| 6193eff38e | |||
| f1929e7cf9 | |||
| 373484c242 | |||
| f77460bb0c | |||
| 574e0dcb05 | |||
| 7b19a0aa08 | |||
| 08642d7618 | |||
| c3e9c27cd3 | |||
| 29a2854671 | |||
| 8e6786e722 | |||
| 6ad40564e3 | |||
| 776973bfe9 | |||
| 6025e43baa | |||
| d9a47f882c | |||
| 4235758a6d | |||
| 59fe2dfabb | |||
| 6364536dcd | |||
| a8a771114d | |||
| 4e0a2c8301 | |||
| b6fed92a17 | |||
| 97b57aeb0c | |||
| e25ed1fff9 | |||
| a2ff5b8a14 | |||
| 0284f18beb | |||
| 803d64c78c | |||
| dacb2f8ace | |||
| b7a53960e5 | |||
| 66f1e6b4fe | |||
| 33166bfafc | |||
| b2648645e8 | |||
| 53e3ddb751 | |||
| edc2dcab92 | |||
| d49f545d94 | 
| @@ -1,5 +0,0 @@ | |||||||
| FROM mcr.microsoft.com/vscode/devcontainers/base:alpine-3.12 |  | ||||||
| RUN apk update |  | ||||||
| RUN apk add --upgrade nodejs-current npm |  | ||||||
| RUN npm i -g pnpm rimraf |  | ||||||
| RUN rimraf node_modules |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
| { |  | ||||||
|   "name": "Node.js", |  | ||||||
|   "build": { |  | ||||||
|     "dockerfile": "Dockerfile" |  | ||||||
|   }, |  | ||||||
|   "settings": { |  | ||||||
|     "terminal.integrated.shell.linux": "/bin/sh" |  | ||||||
|   }, |  | ||||||
|   "extensions": [ |  | ||||||
|     "dbaeumer.vscode-eslint", |  | ||||||
|     "2gua.rainbow-brackets", |  | ||||||
|     "christian-kohler.npm-intellisense", |  | ||||||
|     "remimarsal.prettier-now", |  | ||||||
|     "svelte.svelte-vscode", |  | ||||||
|     "lokalise.i18n-ally", |  | ||||||
|     "fivethree.vscode-svelte-snippets", |  | ||||||
|     "voorjaar.windicss-intellisense" |  | ||||||
|   ], |  | ||||||
|   "postCreateCommand": "yarn && yarn dev --open" |  | ||||||
| } |  | ||||||
| @@ -1,2 +1,4 @@ | |||||||
| public/env.sample.js | public/env.sample.js | ||||||
| .pnpm-store | .pnpm-store | ||||||
|  | .yarn | ||||||
|  | .pnp.* | ||||||
							
								
								
									
										101
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								.drone.yml
									
									
									
									
									
								
							| @@ -1,101 +0,0 @@ | |||||||
| --- |  | ||||||
| kind: secret |  | ||||||
| name: docker_username |  | ||||||
| get: |  | ||||||
|   path: odit-registry-builder |  | ||||||
|   name: username |  | ||||||
|  |  | ||||||
| --- |  | ||||||
| kind: secret |  | ||||||
| name: docker_password |  | ||||||
| get: |  | ||||||
|   path: odit-registry-builder |  | ||||||
|   name: password |  | ||||||
|  |  | ||||||
| --- |  | ||||||
| kind: secret |  | ||||||
| name: git_ssh |  | ||||||
| get: |  | ||||||
|   path: odit-git-bot |  | ||||||
|   name: sshkey |  | ||||||
|  |  | ||||||
| --- |  | ||||||
| kind: secret |  | ||||||
| name: npm_url |  | ||||||
| get: |  | ||||||
|   path: odit-npm-cache |  | ||||||
|   name: url |  | ||||||
|  |  | ||||||
| --- |  | ||||||
| kind: pipeline |  | ||||||
| type: kubernetes |  | ||||||
| name: build:dev |  | ||||||
|  |  | ||||||
| steps: |  | ||||||
|   - name: run full license export |  | ||||||
|     depends_on: ["clone"] |  | ||||||
|     image: registry.odit.services/hub/library/node:19.7.0-alpine3.16 |  | ||||||
|     commands: |  | ||||||
|       - npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8 |  | ||||||
|       - pnpm i |  | ||||||
|       - pnpm licenses:export |  | ||||||
|     environment: |  | ||||||
|       NPM_REGISTRY_URL: |  | ||||||
|         from_secret: npm_url |  | ||||||
|   - name: push new licenses file to repo |  | ||||||
|     depends_on: ["run full license export"] |  | ||||||
|     image: appleboy/drone-git-push |  | ||||||
|     settings: |  | ||||||
|       branch: dev |  | ||||||
|       commit: true |  | ||||||
|       commit_message: new license file version [CI SKIP] |  | ||||||
|       author_email: bot@odit.services |  | ||||||
|       remote: git@git.odit.services:lfk/frontend.git |  | ||||||
|       ssh_key: |  | ||||||
|         from_secret: git_ssh |  | ||||||
|   - name: build dev |  | ||||||
|     depends_on: ["clone"] |  | ||||||
|     image: registry.odit.services/library/drone-kaniko |  | ||||||
|     settings: |  | ||||||
|       username: |  | ||||||
|         from_secret: docker_username |  | ||||||
|       password: |  | ||||||
|         from_secret: docker_password |  | ||||||
|       build_args: |  | ||||||
|         - NPM_REGISTRY_URL: |  | ||||||
|           from_secret: npm_url |  | ||||||
|       repo: lfk/frontend |  | ||||||
|       tags: |  | ||||||
|         - dev |  | ||||||
|       cache: true |  | ||||||
|       registry: registry.odit.services |  | ||||||
| trigger: |  | ||||||
|   branch: |  | ||||||
|     - dev |  | ||||||
|   event: |  | ||||||
|     - push |  | ||||||
|  |  | ||||||
| --- |  | ||||||
| kind: pipeline |  | ||||||
| type: kubernetes |  | ||||||
| name: build:tags |  | ||||||
| steps: |  | ||||||
|   - name: build $DRONE_TAG |  | ||||||
|     depends_on: ["clone"] |  | ||||||
|     image: registry.odit.services/library/drone-kaniko |  | ||||||
|     settings: |  | ||||||
|       username: |  | ||||||
|         from_secret: docker_username |  | ||||||
|       password: |  | ||||||
|         from_secret: docker_password |  | ||||||
|       build_args: |  | ||||||
|         - NPM_REGISTRY_URL: |  | ||||||
|           from_secret: npm_url |  | ||||||
|       repo: lfk/frontend |  | ||||||
|       tags: |  | ||||||
|         - "${DRONE_TAG}" |  | ||||||
|       cache: true |  | ||||||
|       registry: registry.odit.services |  | ||||||
| trigger: |  | ||||||
|   event: |  | ||||||
|     - tag |  | ||||||
							
								
								
									
										33
									
								
								.gitea/workflows/release.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								.gitea/workflows/release.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | name: Build release images | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     tags: | ||||||
|  |       - "*.*.*" | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   build-container: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout | ||||||
|  |         uses: actions/checkout@v4 | ||||||
|  |       - name: Set up Node.js | ||||||
|  |         uses: actions/setup-node@v4 | ||||||
|  |         with: | ||||||
|  |           node-version: 19 | ||||||
|  |       - run: npm i -g pnpm@10.7 && pnpm i | ||||||
|  |       - run: pnpm licenses:export | ||||||
|  |       - name: Login to registry | ||||||
|  |         uses: docker/login-action@v3 | ||||||
|  |         with: | ||||||
|  |           registry: registry.odit.services | ||||||
|  |           username: ${{ vars.REGISTRY_USERNAME }} | ||||||
|  |           password: ${{ secrets.REGISTRY_PASSWORD }} | ||||||
|  |       - name: Set up Docker Buildx | ||||||
|  |         uses: docker/setup-buildx-action@v3 | ||||||
|  |       - name: Build and push | ||||||
|  |         uses: docker/build-push-action@v6 | ||||||
|  |         with: | ||||||
|  |           push: true | ||||||
|  |           tags: | | ||||||
|  |             ${{ vars.REGISTRY }}/lfk/frontend:${{ github.ref_name }} | ||||||
|  |           platforms: linux/amd64,linux/arm64 | ||||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,4 +3,6 @@ node_modules | |||||||
| public/env.js | public/env.js | ||||||
| public/index.html | public/index.html | ||||||
| /dist | /dist | ||||||
| .pnpm-store | .pnpm-store | ||||||
|  | .yarn | ||||||
|  | .pnp.* | ||||||
							
								
								
									
										357
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										357
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -2,8 +2,365 @@ | |||||||
|  |  | ||||||
| All notable changes to this project will be documented in this file. Dates are displayed in UTC. | All notable changes to this project will be documented in this file. Dates are displayed in UTC. | ||||||
|  |  | ||||||
|  | #### [1.10.5](https://git.odit.services/lfk/frontend/compare/1.10.4...1.10.5) | ||||||
|  |  | ||||||
|  | - feat(runners): add distance sorting [`9c3b742`](https://git.odit.services/lfk/frontend/commit/9c3b742a98e17837fbcabe308fb2774dc13b03b8) | ||||||
|  |  | ||||||
|  | #### [1.10.4](https://git.odit.services/lfk/frontend/compare/1.10.3...1.10.4) | ||||||
|  |  | ||||||
|  | > 22 April 2025 | ||||||
|  |  | ||||||
|  | - chore(release): 1.10.4 [`68bf371`](https://git.odit.services/lfk/frontend/commit/68bf3717f9cf15a547c51e245452d4e013f7acad) | ||||||
|  | - fix(runners): Fix runner overview sort [`f88c6e0`](https://git.odit.services/lfk/frontend/commit/f88c6e0dbab620887e180de0d3eab03b8215a477) | ||||||
|  |  | ||||||
|  | #### [1.10.3](https://git.odit.services/lfk/frontend/compare/1.10.2...1.10.3) | ||||||
|  |  | ||||||
|  | > 17 April 2025 | ||||||
|  |  | ||||||
|  | - feat(pdf): Send selfservicelink for generation [`01e77a9`](https://git.odit.services/lfk/frontend/commit/01e77a97f3f28700e0249d35afd9641b56d9c55d) | ||||||
|  | - chore(release): 1.10.3 [`12050cd`](https://git.odit.services/lfk/frontend/commit/12050cdda95b5f8eb5b414b81655d06faae3ef1e) | ||||||
|  | - chore(deps): Bump @odit/lfk-client-js [`10824b5`](https://git.odit.services/lfk/frontend/commit/10824b5d9b207e14a37fa23e90d54337d76e60a9) | ||||||
|  |  | ||||||
|  | #### [1.10.2](https://git.odit.services/lfk/frontend/compare/1.10.1...1.10.2) | ||||||
|  |  | ||||||
|  | > 11 April 2025 | ||||||
|  |  | ||||||
|  | - refactor(runners): filter table for created_via [`785b9e0`](https://git.odit.services/lfk/frontend/commit/785b9e0b60a9961f99d0c519d6bb12dc735ac605) | ||||||
|  | - chore(release): 1.10.2 [`d9870e0`](https://git.odit.services/lfk/frontend/commit/d9870e03bc3175ee9b299174a19f257d6046a718) | ||||||
|  |  | ||||||
|  | #### [1.10.1](https://git.odit.services/lfk/frontend/compare/1.10.0...1.10.1) | ||||||
|  |  | ||||||
|  | > 9 April 2025 | ||||||
|  |  | ||||||
|  | - feat: runner list filtered by created_via [`991716a`](https://git.odit.services/lfk/frontend/commit/991716a7f55d0414111ad264ad1e93de9e82971a) | ||||||
|  | - chore(release): 1.10.1 [`fce2bc6`](https://git.odit.services/lfk/frontend/commit/fce2bc645e040322f4d1b98a1ed1ab5df7227b6d) | ||||||
|  |  | ||||||
|  | #### [1.10.0](https://git.odit.services/lfk/frontend/compare/1.9.11...1.10.0) | ||||||
|  |  | ||||||
|  | > 9 April 2025 | ||||||
|  |  | ||||||
|  | - feat: working CardAssignment [`ac4ef8f`](https://git.odit.services/lfk/frontend/commit/ac4ef8fb6ded5c5d5678a651420e356b3ef45399) | ||||||
|  | - chore(release): 1.10.0 [`aa720f2`](https://git.odit.services/lfk/frontend/commit/aa720f2460079e35eed9d87a2ac580a3305efbd5) | ||||||
|  |  | ||||||
|  | #### [1.9.11](https://git.odit.services/lfk/frontend/compare/1.9.10...1.9.11) | ||||||
|  |  | ||||||
|  | > 8 April 2025 | ||||||
|  |  | ||||||
|  | - feat(dash): add runnersViaKiosk [`5291f8a`](https://git.odit.services/lfk/frontend/commit/5291f8a4d1721cd0c745191ebc85f221c34a23c8) | ||||||
|  | - chore(release): 1.9.11 [`eae0afd`](https://git.odit.services/lfk/frontend/commit/eae0afda23a54020e25821c0188d8cbec3139593) | ||||||
|  |  | ||||||
|  | #### [1.9.10](https://git.odit.services/lfk/frontend/compare/1.9.9...1.9.10) | ||||||
|  |  | ||||||
|  | > 8 April 2025 | ||||||
|  |  | ||||||
|  | - feat: add experimental ui for mobile card assignment [`d7c9c27`](https://git.odit.services/lfk/frontend/commit/d7c9c27ec7a1fea1cbaf26914843d044bbae32fe) | ||||||
|  | - chore(release): 1.9.10 [`e2d7de1`](https://git.odit.services/lfk/frontend/commit/e2d7de1e9e1fd134f54876fa80f19f94fbea3672) | ||||||
|  |  | ||||||
|  | #### [1.9.9](https://git.odit.services/lfk/frontend/compare/1.9.8...1.9.9) | ||||||
|  |  | ||||||
|  | > 4 April 2025 | ||||||
|  |  | ||||||
|  | - chore(release): 1.9.9 [`153b1b3`](https://git.odit.services/lfk/frontend/commit/153b1b3c2badee4826be614c3dbaafc10e1fbfea) | ||||||
|  | - fix(CopyScanStationTokenModal): code sizes [`ec63c7c`](https://git.odit.services/lfk/frontend/commit/ec63c7c1c51ccaf25bdd1eacffda66c820003a4c) | ||||||
|  |  | ||||||
|  | #### [1.9.8](https://git.odit.services/lfk/frontend/compare/1.9.7...1.9.8) | ||||||
|  |  | ||||||
|  | > 2 April 2025 | ||||||
|  |  | ||||||
|  | - feat(GenerateSponsoringContracts): show download progress [`e261d5e`](https://git.odit.services/lfk/frontend/commit/e261d5e345f3175672bf86646ed838dd23400e50) | ||||||
|  | - chore(release): 1.9.8 [`05c2535`](https://git.odit.services/lfk/frontend/commit/05c253569877a45f3c4759262255ca70aa9ee4a3) | ||||||
|  |  | ||||||
|  | #### [1.9.7](https://git.odit.services/lfk/frontend/compare/1.9.6...1.9.7) | ||||||
|  |  | ||||||
|  | > 2 April 2025 | ||||||
|  |  | ||||||
|  | - fix: ImportRunnerModal scrolling & team select [`766eeab`](https://git.odit.services/lfk/frontend/commit/766eeab49fb3ca5715c19dbf9bc53cb71124d3df) | ||||||
|  | - chore(release): 1.9.7 [`c00497d`](https://git.odit.services/lfk/frontend/commit/c00497d7760a935965cc83213f72f35999a3c168) | ||||||
|  |  | ||||||
|  | #### [1.9.6](https://git.odit.services/lfk/frontend/compare/1.9.5...1.9.6) | ||||||
|  |  | ||||||
|  | > 29 March 2025 | ||||||
|  |  | ||||||
|  | - chore(release): 1.9.6 [`3c9b404`](https://git.odit.services/lfk/frontend/commit/3c9b404234c7d7d2f0c48256be2130a0ed8ae047) | ||||||
|  | - pnpm allow builds [`9c56b38`](https://git.odit.services/lfk/frontend/commit/9c56b3883eeab9e1a5e1c4921bfb6528c230e0d4) | ||||||
|  |  | ||||||
|  | #### [1.9.5](https://git.odit.services/lfk/frontend/compare/1.9.4...1.9.5) | ||||||
|  |  | ||||||
|  | > 29 March 2025 | ||||||
|  |  | ||||||
|  | - feat: modal improvements [`d7e84a7`](https://git.odit.services/lfk/frontend/commit/d7e84a79a892294d532cc93aa3391c14a7a5ce99) | ||||||
|  | - chore(release): 1.9.5 [`3d506db`](https://git.odit.services/lfk/frontend/commit/3d506db97502399e8b381b4cf38af2f07a584aec) | ||||||
|  |  | ||||||
|  | #### [1.9.4](https://git.odit.services/lfk/frontend/compare/1.9.3...1.9.4) | ||||||
|  |  | ||||||
|  | > 29 March 2025 | ||||||
|  |  | ||||||
|  | - feat: improve modals [`90b0fec`](https://git.odit.services/lfk/frontend/commit/90b0fec2366b608d163decdcd8798e879cf8218d) | ||||||
|  | - chore(release): 1.9.4 [`102471e`](https://git.odit.services/lfk/frontend/commit/102471eaaae390d3ef815afde9ac4081be7d5dbc) | ||||||
|  |  | ||||||
|  | #### [1.9.3](https://git.odit.services/lfk/frontend/compare/1.9.2...1.9.3) | ||||||
|  |  | ||||||
|  | > 29 March 2025 | ||||||
|  |  | ||||||
|  | - feat: modal improvements [`fbe38ee`](https://git.odit.services/lfk/frontend/commit/fbe38eede95813e163a390b693790d78ce75c215) | ||||||
|  | - feat: modal improvements [`22551c3`](https://git.odit.services/lfk/frontend/commit/22551c379f704b0d9c28c499f7d3f5a37f1533ca) | ||||||
|  | - ci: only tagged runs for now [`e9dffce`](https://git.odit.services/lfk/frontend/commit/e9dffcea835cbcd6b5eb4ed1cc3feb62a9e831db) | ||||||
|  | - chore(release): 1.9.3 [`4883e17`](https://git.odit.services/lfk/frontend/commit/4883e179e7090cf90783dcdecd5df8a422880188) | ||||||
|  | - feat: modal improvements [`13c6e96`](https://git.odit.services/lfk/frontend/commit/13c6e96292613d9619f779f2557201cf0b938753) | ||||||
|  | - feat(OrgDetail): improve selfservice link copy [`f547c0c`](https://git.odit.services/lfk/frontend/commit/f547c0cc817d7db0c70df4059dad753e9b16c1c9) | ||||||
|  | - chore(deps): pnpm@10.7 [`b9563d7`](https://git.odit.services/lfk/frontend/commit/b9563d75dd15519d9ec5d425d628d232e7609913) | ||||||
|  | - fix: sidebar [`a102af5`](https://git.odit.services/lfk/frontend/commit/a102af5a78c83cd54b4981bff2f6c8d54cf8c74c) | ||||||
|  |  | ||||||
|  | #### [1.9.2](https://git.odit.services/lfk/frontend/compare/1.9.1...1.9.2) | ||||||
|  |  | ||||||
|  | > 28 March 2025 | ||||||
|  |  | ||||||
|  | - chore: update lfk client [`f4542ad`](https://git.odit.services/lfk/frontend/commit/f4542adf3b7c757d907c979b989450b64553d750) | ||||||
|  | - feat(dashboard): show runners via selfservice count [`0ee43f8`](https://git.odit.services/lfk/frontend/commit/0ee43f80a65bb5b83d51d6c098bd203bc09e2f1f) | ||||||
|  | - chore(release): 1.9.2 [`3a56942`](https://git.odit.services/lfk/frontend/commit/3a569422ad7d68d0009fa73229dd73ee00be87a9) | ||||||
|  | - refactor: change release message [`9f0623d`](https://git.odit.services/lfk/frontend/commit/9f0623d194a7784d4ede3cb6a6cd10d0aea4a180) | ||||||
|  |  | ||||||
|  | #### [1.9.1](https://git.odit.services/lfk/frontend/compare/1.9.0...1.9.1) | ||||||
|  |  | ||||||
|  | > 28 March 2025 | ||||||
|  |  | ||||||
|  | - refactor: project cleanup [`04897c7`](https://git.odit.services/lfk/frontend/commit/04897c7d2e89cb7e834815907409698ad6758637) | ||||||
|  | - 🚀RELEASE v1.9.1 [`5bab95a`](https://git.odit.services/lfk/frontend/commit/5bab95a9423d9da8c17165732b988ca868f950a5) | ||||||
|  | - feat(RunnerDetail): show created_via [`a4fbaba`](https://git.odit.services/lfk/frontend/commit/a4fbabaf9a0a9a26b6c6782056f11b8a646b8f16) | ||||||
|  | - feat(ConfirmTeamDeletionModal): success toast [`831f369`](https://git.odit.services/lfk/frontend/commit/831f36946d5db777ca77855161f653f861cbd56e) | ||||||
|  |  | ||||||
|  | #### [1.9.0](https://git.odit.services/lfk/frontend/compare/1.8.2...1.9.0) | ||||||
|  |  | ||||||
|  | > 28 March 2025 | ||||||
|  |  | ||||||
|  | - feat: improved ConfirmOrgDeletionModal [`fecf3b5`](https://git.odit.services/lfk/frontend/commit/fecf3b59a320afafee52c95b361edec644c5cbff) | ||||||
|  | - feat: modal improvements [`f5a46aa`](https://git.odit.services/lfk/frontend/commit/f5a46aa203ca2adf2e4e6fe4863629ca80f1becb) | ||||||
|  | - feat: improve ConfirmTeamDeletionModal [`a2cd54f`](https://git.odit.services/lfk/frontend/commit/a2cd54fba4a987f7f7dbab22cc958f9aea2817ff) | ||||||
|  | - feat: improve modals [`443371e`](https://git.odit.services/lfk/frontend/commit/443371e2fdc42506e6e87379bd65facbd8f22d7d) | ||||||
|  | - feat: improve toasts [`481f6b6`](https://git.odit.services/lfk/frontend/commit/481f6b686e77ffa36ee08b62f653d626dd9124c9) | ||||||
|  | - feat: improve modals [`e7a69eb`](https://git.odit.services/lfk/frontend/commit/e7a69ebdca668a5d78b52d092aa1bca6259aa19b) | ||||||
|  | - 🚀RELEASE v1.9.0 [`b7e6fda`](https://git.odit.services/lfk/frontend/commit/b7e6fdaeacf17a7cc77109460b5e2c6d3775ef7b) | ||||||
|  | - feat: improve translations [`d7ab924`](https://git.odit.services/lfk/frontend/commit/d7ab9247cd2eab4f7269b23de5fada76a99ac8bc) | ||||||
|  | - feat: improved translations [`18a4623`](https://git.odit.services/lfk/frontend/commit/18a4623e71dfd942f2268203ce713030acfb2d9d) | ||||||
|  | - feat: improve translations [`9048f3d`](https://git.odit.services/lfk/frontend/commit/9048f3df774df233705a41b08012193447eab803) | ||||||
|  | - feat: improved sidebar z-index [`968a7cc`](https://git.odit.services/lfk/frontend/commit/968a7ccc0e7917bf1a42ac8f85f358880951cc2a) | ||||||
|  | - feat: improved track deletion ui feedback [`194c3c4`](https://git.odit.services/lfk/frontend/commit/194c3c4886e3f3206d76d8634be9d3dd2fa02d8d) | ||||||
|  |  | ||||||
|  | #### [1.8.2](https://git.odit.services/lfk/frontend/compare/1.8.1...1.8.2) | ||||||
|  |  | ||||||
|  | > 26 March 2025 | ||||||
|  |  | ||||||
|  | - feat: improvement of card,certificate,sponsoringcontract action buttons [`7633b7b`](https://git.odit.services/lfk/frontend/commit/7633b7b05671342bc30e0bbecbcd9450e06b5e4d) | ||||||
|  | - 🚀RELEASE v1.8.2 [`6249502`](https://git.odit.services/lfk/frontend/commit/6249502a88ec5bfba6dfbc3ad5ede82d71d0d9e2) | ||||||
|  | - feat(dashboard): active item for teams + runners [`8a78034`](https://git.odit.services/lfk/frontend/commit/8a780340792445fff1f78db994fb78acb5da8304) | ||||||
|  |  | ||||||
|  | #### [1.8.1](https://git.odit.services/lfk/frontend/compare/1.8.0...1.8.1) | ||||||
|  |  | ||||||
|  | > 26 March 2025 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v1.8.1 [`b8e6b24`](https://git.odit.services/lfk/frontend/commit/b8e6b24bf32379c3f4a1679d422e6fdcc45f7c99) | ||||||
|  | - fix(pdf_generation): Only load direct runners for direct calls [`97b7ca9`](https://git.odit.services/lfk/frontend/commit/97b7ca931f607ee64509ad10c2269632fc691091) | ||||||
|  |  | ||||||
|  | #### [1.8.0](https://git.odit.services/lfk/frontend/compare/1.7.0...1.8.0) | ||||||
|  |  | ||||||
|  | > 26 March 2025 | ||||||
|  |  | ||||||
|  | - wip [`824ecfa`](https://git.odit.services/lfk/frontend/commit/824ecfab2e976cd7c6cd2851be8a9be5c6b686e1) | ||||||
|  | - wip [`0a6cf61`](https://git.odit.services/lfk/frontend/commit/0a6cf619b09be837d5503f4695250c7edaeeaff5) | ||||||
|  | - feat: improve fonts + button positions [`c37fb98`](https://git.odit.services/lfk/frontend/commit/c37fb98bed377744981e927ea8d22db9e20c55ca) | ||||||
|  | - 🚀RELEASE v1.8.0 [`48dd9ac`](https://git.odit.services/lfk/frontend/commit/48dd9acde595b882630855d5e6af3cfa18fc9ecf) | ||||||
|  | - wip [`1bc5314`](https://git.odit.services/lfk/frontend/commit/1bc53146b9f024f3cab613b227d29304d687c92b) | ||||||
|  | - wip [`e82350d`](https://git.odit.services/lfk/frontend/commit/e82350df4af082d2bbb322658c6c022d83b819ae) | ||||||
|  | - wip [`37cdbba`](https://git.odit.services/lfk/frontend/commit/37cdbba0a3563875e19bee560f2cd5c8fc2d7a6e) | ||||||
|  | - feat: improve input readability [`79e6a42`](https://git.odit.services/lfk/frontend/commit/79e6a4212d06029766d0a853686ed97879ebd349) | ||||||
|  | - wip [`5f5d827`](https://git.odit.services/lfk/frontend/commit/5f5d8277b98363ef15a92621fca0a209345aca95) | ||||||
|  | - chore(deps): bump [`bb2319a`](https://git.odit.services/lfk/frontend/commit/bb2319a78d253a2d6239a0d3daedc90fd29abdd0) | ||||||
|  | - feat: cleanup TeamDetail + OrgDetail [`f734d1e`](https://git.odit.services/lfk/frontend/commit/f734d1e3f643a500a6432a389c3103045cc51262) | ||||||
|  | - refactor(ci): Switch to actions for dev [`847fa28`](https://git.odit.services/lfk/frontend/commit/847fa288f1b5bbc422cc2944bbe66e80c5a00407) | ||||||
|  | - refactor(ci): Add Gitea workflow for building release images and remove Woodpecker configuration [`3ec18a6`](https://git.odit.services/lfk/frontend/commit/3ec18a696435ada26bf2de2220b190dc630a9759) | ||||||
|  | - feat: athiti font [`391186d`](https://git.odit.services/lfk/frontend/commit/391186d01f3b96638a3569dc2843bf181dc3f02c) | ||||||
|  | - fix(DonorDetail): donor deletion [`5147a20`](https://git.odit.services/lfk/frontend/commit/5147a20b3c4a46968482b1e3517047351c94f77e) | ||||||
|  | - feat(dashboard): full width for sidebar items [`975f145`](https://git.odit.services/lfk/frontend/commit/975f145444e5a478524ea2cbbfb9059b93617185) | ||||||
|  | - wip [`3d3ce29`](https://git.odit.services/lfk/frontend/commit/3d3ce2918bc20cf1080a2b5153ddd8aaf51374b4) | ||||||
|  | - feat(RunnerOrganizationService.runnerOrganizationControllerGetRunners): load all runners in org [`7c10d95`](https://git.odit.services/lfk/frontend/commit/7c10d95c1c68f4842fd323698e004a5ebf2c96cf) | ||||||
|  | - wip [`050a146`](https://git.odit.services/lfk/frontend/commit/050a146ae070d67d8308db4b9612fd6eacbb9923) | ||||||
|  | - fix(ci): Correct tag pattern syntax in release workflow [`e567bb3`](https://git.odit.services/lfk/frontend/commit/e567bb35c3b3f6eb73a2f0bc72f601e70f881ac8) | ||||||
|  |  | ||||||
|  | #### [1.7.0](https://git.odit.services/lfk/frontend/compare/1.6.0...1.7.0) | ||||||
|  |  | ||||||
|  | > 17 December 2024 | ||||||
|  |  | ||||||
|  | - refactor(pdfgeneration): Switch cards over to new service [`e230984`](https://git.odit.services/lfk/frontend/commit/e23098410c7d0b326cdbbb3a4b63fed10611e252) | ||||||
|  | - refactor(pdfgeneration): Switch to new document-server api [`878d971`](https://git.odit.services/lfk/frontend/commit/878d9714cbc0a60cfd96bd1faf8af6af46e6fb5e) | ||||||
|  | - refactor(pdfgeneration): Switched contract generation over to new document-server [`f99b7f4`](https://git.odit.services/lfk/frontend/commit/f99b7f4bb8f166bb966022ddd10689c082d248f0) | ||||||
|  | - refactor(cards): Switched over to new document-server api [`65ce02e`](https://git.odit.services/lfk/frontend/commit/65ce02e777e6e9b3cfed248de680e5f292b3a639) | ||||||
|  | - 🚀RELEASE v1.7.0 [`ae056cd`](https://git.odit.services/lfk/frontend/commit/ae056cd88cb27f003845fa4534553cde841c7f99) | ||||||
|  | - fix(pdfgeneration): Added parent_group [`7f989b2`](https://git.odit.services/lfk/frontend/commit/7f989b206b16e2687d01a38da8e3ea9be0a52ba5) | ||||||
|  |  | ||||||
|  | #### [1.6.0](https://git.odit.services/lfk/frontend/compare/1.5.3...1.6.0) | ||||||
|  |  | ||||||
|  | > 11 December 2024 | ||||||
|  |  | ||||||
|  | - refactor(orgs): Swtich to new selfservice baseurl [`e2d6fbb`](https://git.odit.services/lfk/frontend/commit/e2d6fbb513dc9fe7ce05855edb4b0b4b5daeb07a) | ||||||
|  | - chore: bump [`04494d2`](https://git.odit.services/lfk/frontend/commit/04494d2a2a542f25f785f3bb23e49e5eb0691c0a) | ||||||
|  |  | ||||||
|  | #### [1.5.3](https://git.odit.services/lfk/frontend/compare/1.5.2...1.5.3) | ||||||
|  |  | ||||||
|  | > 26 November 2024 | ||||||
|  |  | ||||||
|  | - feat(dx): Yarn support [`fc15c68`](https://git.odit.services/lfk/frontend/commit/fc15c68cba0d1986563eaf63da3a68784a685a9e) | ||||||
|  | - feat(about): cleanup ui [`84aa846`](https://git.odit.services/lfk/frontend/commit/84aa846b87186b52a2f8632724d4f2cb70af062b) | ||||||
|  | - feat(dashboard): reorder menu items [`e967d8d`](https://git.odit.services/lfk/frontend/commit/e967d8d20c6972b64b0096594a09043553e9c7e5) | ||||||
|  | - fix: unexpected/ missing props [`d803f3d`](https://git.odit.services/lfk/frontend/commit/d803f3d4905d6f792b77d17025467ac13c29068b) | ||||||
|  | - chore(deps): bump some [`68b4309`](https://git.odit.services/lfk/frontend/commit/68b4309164eac40b6fda969b60a7e238985d49f8) | ||||||
|  | - 🚀RELEASE v1.5.3 [`477c650`](https://git.odit.services/lfk/frontend/commit/477c650f3f6dd2eadf5f1cc404e8fc9b02a7841b) | ||||||
|  | - fix(ci): Switch over to new woodpecker version [`7ba890d`](https://git.odit.services/lfk/frontend/commit/7ba890dfd7ba908ebef0338f6faa5e7d804cb5ef) | ||||||
|  | - refactor(ci): Only build licences, don't export [`32b5f54`](https://git.odit.services/lfk/frontend/commit/32b5f5420bf9ff656b713d61b3a0113b9d6cb69f) | ||||||
|  | - feat: cleanup random page toasts [`ad4db88`](https://git.odit.services/lfk/frontend/commit/ad4db882f0f4d00a80ae5e0072e09c071c07ffa2) | ||||||
|  | - fix(ci): Update git pushb settings [`ee87f82`](https://git.odit.services/lfk/frontend/commit/ee87f82799ce559fd43d671ab412f2643eafeac6) | ||||||
|  | - fix(ci): Update relase machanism [`7c08f52`](https://git.odit.services/lfk/frontend/commit/7c08f522aa4b2986544a4c0e5d3261c4c7296121) | ||||||
|  | - fix(ci): Install pnpm [`e211554`](https://git.odit.services/lfk/frontend/commit/e211554579b1f27d13194eff4aad76f6f030141e) | ||||||
|  | - fix(orgs): ImportRunnerModal props [`5468766`](https://git.odit.services/lfk/frontend/commit/5468766d875a6278f01ed1fd9573688374befdd5) | ||||||
|  |  | ||||||
|  | #### [1.5.2](https://git.odit.services/lfk/frontend/compare/1.5.1...1.5.2) | ||||||
|  |  | ||||||
|  | > 21 November 2024 | ||||||
|  |  | ||||||
|  | - feat: improved dashboard titles ui + a11y [`21453ef`](https://git.odit.services/lfk/frontend/commit/21453ef272665c0b7c7b04009b7b74e110fbd988) | ||||||
|  | - feat: improved dashboard titles ui + a11y [`c883920`](https://git.odit.services/lfk/frontend/commit/c883920caaaaef30a8e54dd0e7eecd68943f3041) | ||||||
|  | - feat(dashboard): improved a11y of active sidebar menu item [`a50447f`](https://git.odit.services/lfk/frontend/commit/a50447f457ecc045995efb7b952b07ea09c91373) | ||||||
|  | - feat: improved mobile buttons + search ui [`38fb111`](https://git.odit.services/lfk/frontend/commit/38fb111f7a2b5a1a01b17b00e89ee081e4b91bd9) | ||||||
|  | - feat(i18n/de): rename "Track" to "Laufstrecke" [`1018243`](https://git.odit.services/lfk/frontend/commit/10182433f825968ee55298399b231173698a795c) | ||||||
|  | - 🚀RELEASE v1.5.2 [`3532968`](https://git.odit.services/lfk/frontend/commit/3532968b3399b985b1ed28ba6b89a13f35f9289b) | ||||||
|  | - feat(dashboard): improved mobile ui hamburger button [`b338f33`](https://git.odit.services/lfk/frontend/commit/b338f33a63ad8e98ab44deff2f80dbd5fe2a0fc2) | ||||||
|  | - feat(dashboard): match greeting style with rest of titles [`b1a2044`](https://git.odit.services/lfk/frontend/commit/b1a20446314d1b25e9f653bd2767b072fd629f97) | ||||||
|  | - feat(dashboard): add lfk icon and app name to mobile nav bar [`6bb49db`](https://git.odit.services/lfk/frontend/commit/6bb49db4eee95486f5a947d708b80a7a94d36933) | ||||||
|  | - feat(users/UsersOverview): improve ui by adding borders to badges [`cb82200`](https://git.odit.services/lfk/frontend/commit/cb82200481c629a0dd8b235821115ae4276948ca) | ||||||
|  |  | ||||||
|  | #### [1.5.1](https://git.odit.services/lfk/frontend/compare/1.5.0...1.5.1) | ||||||
|  |  | ||||||
|  | > 21 November 2024 | ||||||
|  |  | ||||||
|  | - chore(deps): pnpm@9 [`35bec9f`](https://git.odit.services/lfk/frontend/commit/35bec9fe584b93cd52e8bab4e469713468a67f70) | ||||||
|  | - chore(deps): bump some [`8fae1fb`](https://git.odit.services/lfk/frontend/commit/8fae1fb6b3e033f789d2568cbd2640c0d163dc53) | ||||||
|  | - fix(scanstations): CopyScanStationTokenModal open after create [`372fa11`](https://git.odit.services/lfk/frontend/commit/372fa110ec402dae166a302f2209c79353983148) | ||||||
|  | - 🚀RELEASE v1.5.1 [`9abf74d`](https://git.odit.services/lfk/frontend/commit/9abf74d6d217e7745c1055bdbfbe97de7b14572f) | ||||||
|  | - fix(config): add explicit window.config [`91d2f46`](https://git.odit.services/lfk/frontend/commit/91d2f46b934bcba1429bd1d96e772c25c42a3e28) | ||||||
|  | - fix(dockerfile): AS casing [`50e81a6`](https://git.odit.services/lfk/frontend/commit/50e81a6cb5773381e153cbec3bed7db820ced84a) | ||||||
|  | - refactor(scanstations/CopyScanStationTokenModal): drop dispatch [`a5e72a1`](https://git.odit.services/lfk/frontend/commit/a5e72a18e368b5a7ee7b4e1894de613ecb767f28) | ||||||
|  | - chore(deps): node:23.2.0 [`93d67bd`](https://git.odit.services/lfk/frontend/commit/93d67bdba90a67b45d8895d9facaf66e908d53d6) | ||||||
|  | - fix(tracks/AddTrackModal): i18n [`c60bae4`](https://git.odit.services/lfk/frontend/commit/c60bae45334c2aa90d8931da07691c196469da46) | ||||||
|  | - fix: tailwind config [`43ac878`](https://git.odit.services/lfk/frontend/commit/43ac878d44b556c6d7811610f6fe0c9a5eff305f) | ||||||
|  |  | ||||||
|  | #### [1.5.0](https://git.odit.services/lfk/frontend/compare/1.4.13...1.5.0) | ||||||
|  |  | ||||||
|  | > 20 November 2024 | ||||||
|  |  | ||||||
|  | - feat(ci)!: Switch to woodpecker [`fb8206f`](https://git.odit.services/lfk/frontend/commit/fb8206ff130f4f65dcf619a2a786e7d5895b77a1) | ||||||
|  | - 🚀RELEASE v1.5.0 [`ceabd06`](https://git.odit.services/lfk/frontend/commit/ceabd06a4319c3c9ffab680f909730d5bd789540) | ||||||
|  | - fix(components): Add missing toast imports [`9bfc0c5`](https://git.odit.services/lfk/frontend/commit/9bfc0c5338933e832d5df50457c7978c026d8df6) | ||||||
|  |  | ||||||
|  | #### [1.4.13](https://git.odit.services/lfk/frontend/compare/1.4.12...1.4.13) | ||||||
|  |  | ||||||
|  | > 31 July 2023 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v1.4.13 [`dceb0ef`](https://git.odit.services/lfk/frontend/commit/dceb0ef46197dc56e29c5f52a5bd8f9fe9b70b27) | ||||||
|  | - Show donations as euro in export [`88bc198`](https://git.odit.services/lfk/frontend/commit/88bc1982cab4481e2e9245f81eff27e095b66a0f) | ||||||
|  | - new license file version [CI SKIP] [`6193eff`](https://git.odit.services/lfk/frontend/commit/6193eff38e1a9d5726bc7d572ab36b921de843d0) | ||||||
|  |  | ||||||
|  | #### [1.4.12](https://git.odit.services/lfk/frontend/compare/1.4.11...1.4.12) | ||||||
|  |  | ||||||
|  | > 18 May 2023 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v1.4.12 [`65f1d22`](https://git.odit.services/lfk/frontend/commit/65f1d222050b0dec81fc847c1921b6135a55ce50) | ||||||
|  | - fix(donation/payment): Funny javascript number to float conversion where integers were needed [`d867c08`](https://git.odit.services/lfk/frontend/commit/d867c08aba234d3a7fe9e2311d37dc5e96fc2afc) | ||||||
|  | - new license file version [CI SKIP] [`08642d7`](https://git.odit.services/lfk/frontend/commit/08642d7618faeae31f0acfe776642c9fa156e5ff) | ||||||
|  |  | ||||||
|  | #### [1.4.11](https://git.odit.services/lfk/frontend/compare/1.4.10...1.4.11) | ||||||
|  |  | ||||||
|  | > 10 May 2023 | ||||||
|  |  | ||||||
|  | - chore(deps): Lockfile [`f77460b`](https://git.odit.services/lfk/frontend/commit/f77460bb0c8ce6d0f3d83a077017d5fc7bf55af7) | ||||||
|  | - 🚀RELEASE v1.4.11 [`373484c`](https://git.odit.services/lfk/frontend/commit/373484c2424bea7ae0d70d342e0ae2076aab1b6a) | ||||||
|  | - feat(orgs): Show total distance [`574e0dc`](https://git.odit.services/lfk/frontend/commit/574e0dcb051305bde2fc76d8456a35baec0cf309) | ||||||
|  | - chore(deps): More bumps [`7b19a0a`](https://git.odit.services/lfk/frontend/commit/7b19a0aa08bb6c89c51d27c0d05777e8fcfdad17) | ||||||
|  |  | ||||||
|  | #### [1.4.10](https://git.odit.services/lfk/frontend/compare/1.4.9...1.4.10) | ||||||
|  |  | ||||||
|  | > 10 May 2023 | ||||||
|  |  | ||||||
|  | - chore(deps): Bumped svelte-table [`29a2854`](https://git.odit.services/lfk/frontend/commit/29a2854671b3af5b85ea96d050a9076f47b6575d) | ||||||
|  | - 🚀RELEASE v1.4.10 [`c3e9c27`](https://git.odit.services/lfk/frontend/commit/c3e9c27cd3d4b916f1661d4958cabab038918587) | ||||||
|  | - chore(deps): Pin and bump [`8e6786e`](https://git.odit.services/lfk/frontend/commit/8e6786e72227b3f07cc805f0957d5b7fd123ec13) | ||||||
|  | - chore(deps): Bumped scanclientjs [`6ad4056`](https://git.odit.services/lfk/frontend/commit/6ad40564e3e342046f6ee19fab9e455ec3bbff9b) | ||||||
|  |  | ||||||
|  | #### [1.4.9](https://git.odit.services/lfk/frontend/compare/1.4.8...1.4.9) | ||||||
|  |  | ||||||
|  | > 9 May 2023 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v1.4.9 [`776973b`](https://git.odit.services/lfk/frontend/commit/776973bfe9b34c26a1c80d5e458cc2644dd9036b) | ||||||
|  | - Changed the in table replacement method [`d9a47f8`](https://git.odit.services/lfk/frontend/commit/d9a47f882c1c6bcf98ef85d50d70c010d54b326e) | ||||||
|  | - Fixed empty return [`6025e43`](https://git.odit.services/lfk/frontend/commit/6025e43baa8516657a60a1de9a82c2189221c6ac) | ||||||
|  |  | ||||||
|  | #### [1.4.8](https://git.odit.services/lfk/frontend/compare/1.4.7...1.4.8) | ||||||
|  |  | ||||||
|  | > 9 May 2023 | ||||||
|  |  | ||||||
|  | - Switched donor loading to non-paginated [`59fe2df`](https://git.odit.services/lfk/frontend/commit/59fe2dfabb224863876c4db31a965c34a51a9369) | ||||||
|  | - 🚀RELEASE v1.4.8 [`4235758`](https://git.odit.services/lfk/frontend/commit/4235758a6d1499715287d6ab193cc87c68d5742e) | ||||||
|  |  | ||||||
|  | #### [1.4.7](https://git.odit.services/lfk/frontend/compare/1.4.6...1.4.7) | ||||||
|  |  | ||||||
|  | > 4 May 2023 | ||||||
|  |  | ||||||
|  | - Paginated modal data loading [`a8a7711`](https://git.odit.services/lfk/frontend/commit/a8a771114df6eb57d5b1d5497a5be49e619d4102) | ||||||
|  | - Moved loading to onmount [`4e0a2c8`](https://git.odit.services/lfk/frontend/commit/4e0a2c83015bde5e360c5fb2c0babbeaa03dc2b5) | ||||||
|  | - 🚀RELEASE v1.4.7 [`6364536`](https://git.odit.services/lfk/frontend/commit/6364536dcd840c71f7cb6afb31bbc4f160ac4f73) | ||||||
|  |  | ||||||
|  | #### [1.4.6](https://git.odit.services/lfk/frontend/compare/1.4.5...1.4.6) | ||||||
|  |  | ||||||
|  | > 4 May 2023 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v1.4.6 [`b6fed92`](https://git.odit.services/lfk/frontend/commit/b6fed92a176af1c975484d9146ee5634e0031401) | ||||||
|  | - fix(donor/details): don't load donations [`a2ff5b8`](https://git.odit.services/lfk/frontend/commit/a2ff5b8a142ce4e6b8876f64935f9787ec44a51e) | ||||||
|  | - fix(donor/detail): Set email to null to avoid vaidation errors [`97b57ae`](https://git.odit.services/lfk/frontend/commit/97b57aeb0cc9058542a36dea9c8b2852169c250f) | ||||||
|  | - fix(donor/detail): Set phone to null to avoid vaidation errors [`e25ed1f`](https://git.odit.services/lfk/frontend/commit/e25ed1fff9b200605d5d2b78238b774ec7289aaa) | ||||||
|  |  | ||||||
|  | #### [1.4.5](https://git.odit.services/lfk/frontend/compare/1.4.4...1.4.5) | ||||||
|  |  | ||||||
|  | > 4 May 2023 | ||||||
|  |  | ||||||
|  | - Revert "revert: buggy pagination" [`dacb2f8`](https://git.odit.services/lfk/frontend/commit/dacb2f8ace373f6594fc64af133971af053f00c0) | ||||||
|  | - fix: Removed dynamic pagesize adjustments [`803d64c`](https://git.odit.services/lfk/frontend/commit/803d64c78caa570d31d6055e70e2d2af6834f04b) | ||||||
|  | - 🚀RELEASE v1.4.5 [`0284f18`](https://git.odit.services/lfk/frontend/commit/0284f18beb8b24d4d4d071eca13bc5868666232c) | ||||||
|  |  | ||||||
|  | #### [1.4.4](https://git.odit.services/lfk/frontend/compare/1.4.3...1.4.4) | ||||||
|  |  | ||||||
|  | > 4 May 2023 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v1.4.4 [`b7a5396`](https://git.odit.services/lfk/frontend/commit/b7a53960e5f37ae089d77bc11668d917145e2abb) | ||||||
|  | - fix(AddDonationModal): missing toast dismiss on success distance donation [`66f1e6b`](https://git.odit.services/lfk/frontend/commit/66f1e6b4fe1350ee79673a0aff97e36f44179c92) | ||||||
|  |  | ||||||
|  | #### [1.4.3](https://git.odit.services/lfk/frontend/compare/1.4.2...1.4.3) | ||||||
|  |  | ||||||
|  | > 4 May 2023 | ||||||
|  |  | ||||||
|  | - revert: buggy pagination [`b264864`](https://git.odit.services/lfk/frontend/commit/b2648645e8fc05f8742ecfc592557f954261671b) | ||||||
|  | - 🚀RELEASE v1.4.3 [`33166bf`](https://git.odit.services/lfk/frontend/commit/33166bfafcffb9d86dfc7dfcd2cb8ba5c85da7e7) | ||||||
|  |  | ||||||
|  | #### [1.4.2](https://git.odit.services/lfk/frontend/compare/1.4.1...1.4.2) | ||||||
|  |  | ||||||
|  | > 4 May 2023 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v1.4.2 [`53e3ddb`](https://git.odit.services/lfk/frontend/commit/53e3ddb751c1150a4640ae6302e4df5b88cedc51) | ||||||
|  | - fix(GenerateRunnerCertificates): missing toast import [`d49f545`](https://git.odit.services/lfk/frontend/commit/d49f545d94acabc0c96860f212466b7a4cbe7dab) | ||||||
|  | - fix(DonorDetail): missing toast import [`edc2dca`](https://git.odit.services/lfk/frontend/commit/edc2dcab92c3cace05335a283a849c3c978ec8ec) | ||||||
|  |  | ||||||
| #### [1.4.1](https://git.odit.services/lfk/frontend/compare/1.4.0...1.4.1) | #### [1.4.1](https://git.odit.services/lfk/frontend/compare/1.4.0...1.4.1) | ||||||
|  |  | ||||||
|  | > 1 May 2023 | ||||||
|  |  | ||||||
|  | - 🚀RELEASE v1.4.1 [`3b98c99`](https://git.odit.services/lfk/frontend/commit/3b98c99b72f24b8552e2b2334f13622bdf6ef90d) | ||||||
| - Fixed translation [`1da775a`](https://git.odit.services/lfk/frontend/commit/1da775a09b8be90a49e06aed16df917d221ee989) | - Fixed translation [`1da775a`](https://git.odit.services/lfk/frontend/commit/1da775a09b8be90a49e06aed16df917d221ee989) | ||||||
|  |  | ||||||
| #### [1.4.0](https://git.odit.services/lfk/frontend/compare/1.3.4...1.4.0) | #### [1.4.0](https://git.odit.services/lfk/frontend/compare/1.3.4...1.4.0) | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| FROM registry.odit.services/hub/library/node:20.0.0-alpine3.17 as build | FROM registry.odit.services/hub/library/node:23.10.0-alpine3.21 AS build | ||||||
| ARG NPM_REGISTRY_URL=https://registry.npmjs.org | ARG NPM_REGISTRY_URL=https://registry.npmjs.org | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
|  |  | ||||||
| COPY package.json pnpm-lock.yaml vite.config.js tailwind.config.js postcss.config.cjs index.html ./ | COPY package.json pnpm-lock.yaml vite.config.js tailwind.config.cjs postcss.config.cjs index.html ./ | ||||||
| RUN npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@8 | RUN npm config set registry $NPM_REGISTRY_URL && npm i -g pnpm@10.7 | ||||||
| RUN mkdir /pnpm && pnpm config set store-dir /pnpm && pnpm i | RUN mkdir /pnpm && pnpm config set store-dir /pnpm && pnpm i | ||||||
|  |  | ||||||
| COPY src ./src | COPY src ./src | ||||||
| @@ -11,6 +11,6 @@ COPY public ./public | |||||||
| RUN pnpm build | RUN pnpm build | ||||||
|  |  | ||||||
| # final image | # final image | ||||||
| FROM registry.odit.services/library/nginx-brotli:3.15 as final | FROM registry.odit.services/library/nginx-brotli:3.15 AS final | ||||||
| COPY --from=build /app/dist /usr/share/nginx/html | COPY --from=build /app/dist /usr/share/nginx/html | ||||||
| COPY ./nginx.conf /etc/nginx/nginx.conf | COPY ./nginx.conf /etc/nginx/nginx.conf | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| <!DOCTYPE html> | <!doctype html> | ||||||
| <html lang="en"> | <html lang="en"> | ||||||
|   <head> |   <head> | ||||||
|     <meta charset="utf-8" /> |     <meta charset="utf-8" /> | ||||||
| @@ -13,7 +13,7 @@ | |||||||
|  |  | ||||||
|   <body> |   <body> | ||||||
|     <span style="display: none; visibility: hidden" id="buildinfo" |     <span style="display: none; visibility: hidden" id="buildinfo" | ||||||
|       >RELEASE_INFO-1.4.1-RELEASE_INFO</span |       >RELEASE_INFO-1.10.5-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> | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "@odit/lfk-frontend", |   "name": "@odit/lfk-frontend", | ||||||
|   "version": "1.4.1", |   "version": "1.10.5", | ||||||
|   "type": "module", |   "type": "module", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "i18n-order": "node order.js", |     "i18n-order": "node order.js", | ||||||
| @@ -12,27 +12,27 @@ | |||||||
|   }, |   }, | ||||||
|   "license": "CC-BY-NC-SA-4.0", |   "license": "CC-BY-NC-SA-4.0", | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@odit/license-exporter": "0.0.12", |     "@odit/license-exporter": "0.2.0", | ||||||
|     "@sveltejs/vite-plugin-svelte": "2.1.1", |     "@sveltejs/vite-plugin-svelte": "2.1.1", | ||||||
|     "auto-changelog": "2.4.0", |     "auto-changelog": "2.5.0", | ||||||
|     "autoprefixer": "10.4.14", |     "autoprefixer": "10.4.21", | ||||||
|     "postcss": "8.4.23", |     "postcss": "8.5.3", | ||||||
|     "prettier": "^2.8.8", |     "prettier": "3.5.3", | ||||||
|     "prettier-plugin-svelte": "^2.10.0", |     "prettier-plugin-svelte": "3.3.3", | ||||||
|     "release-it": "15.10.1", |     "release-it": "17.10.0", | ||||||
|     "svelte-select": "3.17.0", |     "svelte-select": "3.17.0", | ||||||
|     "tailwindcss": "3.3.2", |     "tailwindcss": "3.4.15", | ||||||
|     "vite": "4.3.3" |     "vite": "4.3.3" | ||||||
|   }, |   }, | ||||||
|   "release-it": { |   "release-it": { | ||||||
|     "git": { |     "git": { | ||||||
|       "commit": true, |       "commit": true, | ||||||
|       "requireCleanWorkingDir": false, |       "requireCleanWorkingDir": false, | ||||||
|       "commitMessage": "🚀RELEASE v${version}", |       "commitMessage": "chore(release): ${version}", | ||||||
|       "push": true, |       "push": true, | ||||||
|       "tag": true, |       "tag": true, | ||||||
|       "tagName": null, |       "tagName": "${version}", | ||||||
|       "tagAnnotation": "v${version}" |       "tagAnnotation": "${version}" | ||||||
|     }, |     }, | ||||||
|     "npm": { |     "npm": { | ||||||
|       "publish": false |       "publish": false | ||||||
| @@ -42,19 +42,21 @@ | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@odit/lfk-client-js": "1.1.1", |     "@fontsource/athiti": "^5.2.5", | ||||||
|     "@paralleldrive/cuid2": "^2.2.0", |     "@odit/lfk-client-js": "1.2.4", | ||||||
|     "@tanstack/svelte-table": "^8.8.6", |     "@paralleldrive/cuid2": "2.2.2", | ||||||
|     "bwip-js": "^3.4.0", |     "@tanstack/svelte-table": "8.9.1", | ||||||
|     "check-password-strength": "2.0.7", |     "bwip-js": "3.4.0", | ||||||
|  |     "check-password-strength": "2.0.10", | ||||||
|     "csvtojson": "2.0.10", |     "csvtojson": "2.0.10", | ||||||
|  |     "html5-qrcode": "^2.3.8", | ||||||
|     "localforage": "1.10.0", |     "localforage": "1.10.0", | ||||||
|     "marked": "4.3.0", |     "marked": "4.3.0", | ||||||
|     "svelte": "3.58.0", |     "svelte": "3.58.0", | ||||||
|     "svelte-french-toast": "1.0.4-beta.0", |     "svelte-french-toast": "1.2.0", | ||||||
|     "svelte-i18n": "3.6.0", |     "svelte-i18n": "3.6.0", | ||||||
|     "tinro": "0.6.12", |     "tinro": "0.6.12", | ||||||
|     "validator": "13.9.0", |     "validator": "13.15.0", | ||||||
|     "xlsx": "0.18.5" |     "xlsx": "0.18.5" | ||||||
|   }, |   }, | ||||||
|   "volta": { |   "volta": { | ||||||
|   | |||||||
							
								
								
									
										5597
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5597
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | onlyBuiltDependencies: | ||||||
|  |   - es5-ext | ||||||
|  |   - esbuild | ||||||
							
								
								
									
										
											BIN
										
									
								
								public/beep.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/beep.mp3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,5 +1,6 @@ | |||||||
| const config = { | const config = { | ||||||
|   baseurl: "http://localhost:4010", |   baseurl: "http://localhost:4010", | ||||||
|  |   baseurl_selfservice: "http://localhost:5174", | ||||||
|   baseurl_documentserver: "http://localhost:4010/documents", |   baseurl_documentserver: "http://localhost:4010/documents", | ||||||
|   documentserver_key: |   documentserver_key: | ||||||
|     "NqZSYTy5AFQ7MppbLW5moqpTk7u7YrNUHKYhKYuThnnya2WpCOIU694hIZT1FzYe", |     "NqZSYTy5AFQ7MppbLW5moqpTk7u7YrNUHKYhKYuThnnya2WpCOIU694hIZT1FzYe", | ||||||
| @@ -8,3 +9,4 @@ const config = { | |||||||
|   default_password: "demo", |   default_password: "demo", | ||||||
|   prefersHashRouting: true, |   prefersHashRouting: true, | ||||||
| }; | }; | ||||||
|  | window.config = config; | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -1,4 +0,0 @@ | |||||||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98.1 118"> |  | ||||||
|   <path fill="#ff3e00" d="M91.8 15.6C80.9-.1 59.2-4.7 43.6 5.2L16.1 22.8A31.25 31.25 0 001.9 43.9c-1.3 7.3-.2 14.8 3.3 21.3-2.4 3.6-4 7.6-4.7 11.8-1.6 8.9.5 18.1 5.7 25.4 11 15.7 32.6 20.3 48.2 10.4l27.5-17.5c7.5-4.7 12.7-12.4 14.2-21.1 1.3-7.3.2-14.8-3.3-21.3 2.4-3.6 4-7.6 4.7-11.8 1.7-9-.4-18.2-5.7-25.5"/> |  | ||||||
|   <path fill="#fff" d="M40.9 103.9a21.8 21.8 0 01-23.4-8.7c-3.2-4.4-4.4-9.9-3.5-15.3l.6-2.6.5-1.6 1.4 1c3.3 2.4 6.9 4.2 10.8 5.4l1 .3-.1 1c-.1 1.4.3 2.9 1.1 4.1a6.62 6.62 0 008.8 2L65.5 72c1.4-.9 2.3-2.2 2.6-3.8.3-1.6-.1-3.3-1-4.6a6.56 6.56 0 00-8.8-1.9l-10.5 6.7a18.6 18.6 0 01-5.6 2.4 21.8 21.8 0 01-23.4-8.7 20.2 20.2 0 01-3.4-15.3c.9-5.2 4.1-9.9 8.6-12.7l27.5-17.5c1.7-1.1 3.6-1.9 5.6-2.5a21.8 21.8 0 0123.4 8.7c3.2 4.4 4.4 9.9 3.5 15.3-.2.9-.4 1.7-.7 2.6l-.5 1.6-1.4-1c-3.3-2.4-6.9-4.2-10.8-5.4l-1-.3.1-1c.1-1.4-.3-2.9-1.1-4.1a6.56 6.56 0 00-8.8-1.9L32.4 46.1c-1.4.9-2.3 2.2-2.6 3.8s.1 3.3 1 4.6a6.56 6.56 0 008.8 1.9l10.5-6.7c1.7-1.1 3.6-1.9 5.6-2.5a21.8 21.8 0 0123.4 8.7c3.2 4.4 4.4 9.9 3.5 15.3-.9 5.2-4.1 9.9-8.6 12.7l-27.5 17.5c-1.7 1.1-3.6 1.9-5.6 2.5"/> |  | ||||||
| </svg> |  | ||||||
| Before Width: | Height: | Size: 1.1 KiB | 
| @@ -41,6 +41,7 @@ | |||||||
|   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 CardAssignment from "./components/general/CardAssignment.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"; | ||||||
| @@ -135,12 +136,17 @@ | |||||||
|         </Route> |         </Route> | ||||||
|         <Route path="/runners/*"> |         <Route path="/runners/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Runners /> |             <Runners created_via="all" /> | ||||||
|           </Route> |           </Route> | ||||||
|           <Route path="/:runnerid" let:params> |           <Route path="/:runnerid" let:params> | ||||||
|             <RunnerDetail {params} /> |             <RunnerDetail {params} /> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|  |         <Route path="/cardassignment/*"> | ||||||
|  |           <Route path="/"> | ||||||
|  |             <CardAssignment /> | ||||||
|  |           </Route> | ||||||
|  |         </Route> | ||||||
|         <Route path="/teams/*"> |         <Route path="/teams/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Teams /> |             <Teams /> | ||||||
|   | |||||||
| @@ -20,7 +20,6 @@ | |||||||
|         OpenAPI.TOKEN = value.access_token; |         OpenAPI.TOKEN = value.access_token; | ||||||
|         const jwtinfo = JSON.parse(atob(OpenAPI.TOKEN.split(".")[1])); |         const jwtinfo = JSON.parse(atob(OpenAPI.TOKEN.split(".")[1])); | ||||||
|         store.login(value, jwtinfo); |         store.login(value, jwtinfo); | ||||||
|         toast($_("welcome_wavinghand")); |  | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| @@ -50,7 +49,6 @@ | |||||||
|           store.login(result.access_token, jwtinfo); |           store.login(result.access_token, jwtinfo); | ||||||
|           location.replace("/"); |           location.replace("/"); | ||||||
|           toast.dismiss(); |           toast.dismiss(); | ||||||
|           toast($_("welcome_wavinghand")); |  | ||||||
|         }) |         }) | ||||||
|         .catch((err) => { |         .catch((err) => { | ||||||
|           toast.dismiss(); |           toast.dismiss(); | ||||||
|   | |||||||
| @@ -5,8 +5,11 @@ | |||||||
|   import { RunnerCardService } from "@odit/lfk-client-js"; |   import { RunnerCardService } from "@odit/lfk-client-js"; | ||||||
|   import { createEventDispatcher } from "svelte"; |   import { createEventDispatcher } from "svelte"; | ||||||
|   import toast from "svelte-french-toast"; |   import toast from "svelte-french-toast"; | ||||||
|  |   import DocumentServer from "../pdf_generation/DocumentServer"; | ||||||
|   export let bulk_modal_open; |   export let bulk_modal_open; | ||||||
|   const dispatch = createEventDispatcher(); |   const dispatch = createEventDispatcher(); | ||||||
|  |   const documentServer = new DocumentServer(config.baseurl_documentserver,config.documentserver_key); | ||||||
|  |  | ||||||
|  |  | ||||||
|   $: card_count = 0; |   $: card_count = 0; | ||||||
|   $: is_card_count_valid = card_count > 0; |   $: is_card_count_valid = card_count > 0; | ||||||
| @@ -60,24 +63,7 @@ | |||||||
|           toast.success($_("created-blanco-cards")); |           toast.success($_("created-blanco-cards")); | ||||||
|           toast.loading($_("generating-pdf")); |           toast.loading($_("generating-pdf")); | ||||||
|           dispatch("created", { cards: result }); |           dispatch("created", { cards: result }); | ||||||
|           fetch( |           documentServer.generateCards(result, "de") | ||||||
|             `${config.baseurl_documentserver}/cards?&download=true&key=${config.documentserver_key}`, |  | ||||||
|             { |  | ||||||
|               method: "POST", |  | ||||||
|               headers: { |  | ||||||
|                 "Content-Type": "application/json", |  | ||||||
|               }, |  | ||||||
|               body: JSON.stringify(result), |  | ||||||
|             } |  | ||||||
|           ) |  | ||||||
|             .then((response) => { |  | ||||||
|               if (response.status != "200") { |  | ||||||
|                 toast.dismiss(); |  | ||||||
|                 toast.error($_("pdf-generation-failed")); |  | ||||||
|               } else { |  | ||||||
|                 return response.blob(); |  | ||||||
|               } |  | ||||||
|             }) |  | ||||||
|             .then((blob) => { |             .then((blob) => { | ||||||
|               const url = window.URL.createObjectURL(blob); |               const url = window.URL.createObjectURL(blob); | ||||||
|               let a = document.createElement("a"); |               let a = document.createElement("a"); | ||||||
| @@ -105,14 +91,14 @@ | |||||||
|  |  | ||||||
| {#if bulk_modal_open} | {#if bulk_modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       bulk_modal_open = false; |       bulk_modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -130,10 +116,10 @@ | |||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w- rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -149,18 +135,18 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:mt-0"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("create-bulk-blanco-cards")} |                 {$_("create-bulk-blanco-cards")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "just-enter-how-many-you-want-and-the-system-will-create-them" |                     "just-enter-how-many-you-want-and-the-system-will-create-them" | ||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="amount" |                     for="amount" | ||||||
| @@ -177,7 +163,7 @@ | |||||||
|                       type="number" |                       type="number" | ||||||
|                       step="1" |                       step="1" | ||||||
|                       name="amount" |                       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" |                       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-neutral-800 p-2" | ||||||
|                       placeholder="400" |                       placeholder="400" | ||||||
|                     /> |                     /> | ||||||
|                     <span |                     <span | ||||||
| @@ -197,13 +183,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit_with_print} |             on:click={submit_with_print} | ||||||
|             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" | ||||||
|           > |           > | ||||||
|             {$_("create-and-generate-pdf")} |             {$_("create-and-generate-pdf")} | ||||||
|           </button> |           </button> | ||||||
| @@ -212,7 +198,7 @@ | |||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit_without_print} |             on:click={submit_without_print} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-400 text-base font-medium text-white hover:bg-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-400 text-base font-medium text-white hover:bg-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("create-without-pdf")} |             {$_("create-without-pdf")} | ||||||
|           </button> |           </button> | ||||||
| @@ -221,7 +207,7 @@ | |||||||
|               bulk_modal_open = false; |               bulk_modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mr-auto mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="mr-auto 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" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -84,14 +84,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -104,15 +104,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -128,11 +128,11 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:mt-0"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("create-a-new-card")} |                 {$_("create-a-new-card")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_("you-can-provide-a-runner-but-you-dont-have-to")} |                   {$_("you-can-provide-a-runner-but-you-dont-have-to")} | ||||||
|                   {$_( |                   {$_( | ||||||
| @@ -140,7 +140,7 @@ | |||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="donor" |                     for="donor" | ||||||
| @@ -148,7 +148,7 @@ | |||||||
|                     >{$_("runner")}</label |                     >{$_("runner")}</label | ||||||
|                   > |                   > | ||||||
|                   <Select |                   <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" |                     containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     itemFilter={(label, filterText, option) => |                     itemFilter={(label, filterText, option) => | ||||||
|                       filterRunners(label, filterText, option)} |                       filterRunners(label, filterText, option)} | ||||||
|                     items={runners} |                     items={runners} | ||||||
| @@ -165,13 +165,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("create")} |             {$_("create")} | ||||||
|           </button> |           </button> | ||||||
| @@ -180,7 +180,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -78,14 +78,14 @@ | |||||||
|  |  | ||||||
| {#if edit_modal_open} | {#if edit_modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       edit_modal_open = false; |       edit_modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -98,15 +98,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -122,16 +122,16 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("edit-a-card")} |                 {$_("edit-a-card")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_("you-can-provide-a-runner-but-you-dont-have-to")} |                   {$_("you-can-provide-a-runner-but-you-dont-have-to")} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="runner" |                     for="runner" | ||||||
| @@ -139,7 +139,7 @@ | |||||||
|                     >{$_("runner")}</label |                     >{$_("runner")}</label | ||||||
|                   > |                   > | ||||||
|                   <Select |                   <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" |                     containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     itemFilter={(label, filterText, option) => |                     itemFilter={(label, filterText, option) => | ||||||
|                       filterRunners(label, filterText, option)} |                       filterRunners(label, filterText, option)} | ||||||
|                     items={runners} |                     items={runners} | ||||||
| @@ -174,13 +174,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("save-changes")} |             {$_("save-changes")} | ||||||
|           </button> |           </button> | ||||||
| @@ -189,7 +189,7 @@ | |||||||
|               edit_modal_open = false; |               edit_modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -5,12 +5,12 @@ | |||||||
|  |  | ||||||
| {#if enabled} | {#if enabled} | ||||||
|   <span |   <span | ||||||
|     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800" |     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-100 text-green-800" | ||||||
|     >{$_("enabled")}</span |     >{$_("enabled")}</span | ||||||
|   > |   > | ||||||
| {:else} | {:else} | ||||||
|   <span |   <span | ||||||
|     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800" |     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-red-100 text-red-800" | ||||||
|     >{$_("disabled")}</span |     >{$_("disabled")}</span | ||||||
|   > |   > | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -11,29 +11,29 @@ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> |   <h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_("cards")} |     {$_("cards")} | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("CARD:CREATE")} |   </h4> | ||||||
|       <button |   {#if store.state.jwtinfo.userdetails.permissions.includes("CARD:CREATE")} | ||||||
|         on:click={() => { |     <button | ||||||
|           modal_open = true; |       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" |       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:w-auto sm:text-sm  mb-1 lg:mb-0" | ||||||
|         {$_("add-card")} |     > | ||||||
|       </button> |       {$_("add-card")} | ||||||
|       <button |     </button> | ||||||
|         on:click={() => { |     <button | ||||||
|           bulk_modal_open = true; |       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" |       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:w-auto sm:text-sm  mb-1 lg:mb-0" | ||||||
|         {$_("create-bulk-cards")} |     > | ||||||
|       </button> |       {$_("create-bulk-cards")} | ||||||
|     {/if} |     </button> | ||||||
|   </span> |   {/if} | ||||||
|   <CardsOverview bind:current_cards bind:addCards /> |   <CardsOverview bind:current_cards bind:addCards /> | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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="m-auto" style="height:15rem" src={cards_empty} alt="" /> |     <img class="m-auto mt-2" style="height:15rem" src={cards_empty} alt="" /> | ||||||
|     <span class="font-bold">{$_("there-are-no-cards-yet")}</span><br /> |     <span class="font-bold">{$_("there-are-no-cards-yet")}</span><br /> | ||||||
|     <span>{$_("add-your-first-card")}</span> |     <span>{$_("add-your-first-card")}</span> | ||||||
|   </p> |   </p> | ||||||
|   | |||||||
| @@ -151,9 +151,8 @@ | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   onMount(async () => { |   onMount(async () => { | ||||||
|     toast.loading($_("loading-cards")); |  | ||||||
|     let page = 0; |     let page = 0; | ||||||
|     let pagesize = 100; |     let pagesize = 500; | ||||||
|     while (page >= 0) { |     while (page >= 0) { | ||||||
|       const cards = await RunnerCardService.runnerCardControllerGetAll( |       const cards = await RunnerCardService.runnerCardControllerGetAll( | ||||||
|         page, |         page, | ||||||
| @@ -171,10 +170,7 @@ | |||||||
|  |  | ||||||
|       dataLoaded = true; |       dataLoaded = true; | ||||||
|       page++; |       page++; | ||||||
|       pagesize += 100; |  | ||||||
|     } |     } | ||||||
|     toast.dismiss(); |  | ||||||
|     toast.success($_("all-cards-loaded")); |  | ||||||
|   }); |   }); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| @@ -220,7 +216,7 @@ | |||||||
|       {#if selected.length > 0} |       {#if selected.length > 0} | ||||||
|         <button |         <button | ||||||
|           type="button" |           type="button" | ||||||
|           class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm inline-flex" |           class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm inline-flex" | ||||||
|           id="options-menu" |           id="options-menu" | ||||||
|           on:click={async () => { |           on:click={async () => { | ||||||
|             const prom = []; |             const prom = []; | ||||||
|   | |||||||
| @@ -34,14 +34,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -54,15 +54,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -78,15 +78,10 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("confirm-delete")} |                 {$_("please-confirm-the-deletion-of-card")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |  | ||||||
|                 <p class="text-sm text-gray-500"> |  | ||||||
|                   {$_("please-confirm-the-deletion-of-card")} |  | ||||||
|                 </p> |  | ||||||
|               </div> |  | ||||||
|               <div class="w-full"> |               <div class="w-full"> | ||||||
|                 {$_("card")} #{delete_card.code}<br /> |                 {$_("card")} #{delete_card.code}<br /> | ||||||
|                 <span class="inline-block"> |                 <span class="inline-block"> | ||||||
| @@ -104,11 +99,11 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-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" | ||||||
|           > |           > | ||||||
|             {$_("delete")} |             {$_("delete")} | ||||||
|           </button> |           </button> | ||||||
| @@ -117,7 +112,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -43,7 +43,7 @@ | |||||||
|   $: address_zipcode_value = ""; |   $: address_zipcode_value = ""; | ||||||
|   $: address_city_value = ""; |   $: address_city_value = ""; | ||||||
|   $: processed_last_submit = true; |   $: processed_last_submit = true; | ||||||
|   $: address_checked = true; |   $: address_checked = false; | ||||||
|   $: isPhoneValidOrEmpty = |   $: isPhoneValidOrEmpty = | ||||||
|     (phone_input_value.includes("+") && |     (phone_input_value.includes("+") && | ||||||
|       isMobilePhone( |       isMobilePhone( | ||||||
| @@ -136,14 +136,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -156,15 +156,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -179,18 +179,18 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("create-a-new-contact")} |                 {$_("create-a-new-contact")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "please-provide-the-required-information-to-add-a-new-contact" |                     "please-provide-the-required-information-to-add-a-new-contact" | ||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="firstname" |                     for="firstname" | ||||||
| @@ -208,7 +208,7 @@ | |||||||
|                     bind:this={firstname_input} |                     bind:this={firstname_input} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="firstname" |                     name="firstname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isFirstnameValid} |                   {#if !isFirstnameValid} | ||||||
|                     <span |                     <span | ||||||
| @@ -231,7 +231,7 @@ | |||||||
|                     bind:this={middlename_input} |                     bind:this={middlename_input} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="trackname" |                     name="trackname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
| @@ -250,7 +250,7 @@ | |||||||
|                     bind:this={lastname_input} |                     bind:this={lastname_input} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="lastname" |                     name="lastname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isLastnameValid} |                   {#if !isLastnameValid} | ||||||
|                     <span |                     <span | ||||||
| @@ -270,7 +270,7 @@ | |||||||
|                     name="team" |                     name="team" | ||||||
|                     multiple |                     multiple | ||||||
|                     bind:value={selected_team} |                     bind:value={selected_team} | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   > |                   > | ||||||
|                     {#each teams as team} |                     {#each teams as team} | ||||||
|                       <option value={team.id}> |                       <option value={team.id}> | ||||||
| @@ -300,7 +300,7 @@ | |||||||
|                     bind:this={phone_input} |                     bind:this={phone_input} | ||||||
|                     type="tel" |                     type="tel" | ||||||
|                     name="phone" |                     name="phone" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isPhoneValidOrEmpty} |                   {#if !isPhoneValidOrEmpty} | ||||||
|                     <span |                     <span | ||||||
| @@ -328,7 +328,7 @@ | |||||||
|                     bind:this={email_input} |                     bind:this={email_input} | ||||||
|                     type="email" |                     type="email" | ||||||
|                     name="email" |                     name="email" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isEmailValidOrEmpty} |                   {#if !isEmailValidOrEmpty} | ||||||
|                     <span |                     <span | ||||||
| @@ -349,7 +349,7 @@ | |||||||
|                     /> |                     /> | ||||||
|                   </div> |                   </div> | ||||||
|                   <div class="ml-3 text-sm"> |                   <div class="ml-3 text-sm"> | ||||||
|                     <label for="comments" class="font-medium text-gray-700" |                     <label for="comments" class="font-semibold text-gray-700" | ||||||
|                       >{$_("address")}</label |                       >{$_("address")}</label | ||||||
|                     > |                     > | ||||||
|                   </div> |                   </div> | ||||||
| @@ -371,7 +371,7 @@ | |||||||
|                       bind:this={address_input1} |                       bind:this={address_input1} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="address1" |                       name="address1" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                     {#if !isAddress1Valid} |                     {#if !isAddress1Valid} | ||||||
|                       <span |                       <span | ||||||
| @@ -394,7 +394,7 @@ | |||||||
|                       bind:this={address_input2} |                       bind:this={address_input2} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="address2" |                       name="address2" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                   </div> |                   </div> | ||||||
|                   <div class="col-span-6"> |                   <div class="col-span-6"> | ||||||
| @@ -413,7 +413,7 @@ | |||||||
|                       bind:this={address_zipcode} |                       bind:this={address_zipcode} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="zipcode" |                       name="zipcode" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                     {#if !iszipcodevalid} |                     {#if !iszipcodevalid} | ||||||
|                       <span |                       <span | ||||||
| @@ -439,7 +439,7 @@ | |||||||
|                       bind:this={address_city} |                       bind:this={address_city} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="city" |                       name="city" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                     {#if !iscityvalid} |                     {#if !iscityvalid} | ||||||
|                       <span |                       <span | ||||||
| @@ -454,13 +454,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("create")} |             {$_("create")} | ||||||
|           </button> |           </button> | ||||||
| @@ -469,7 +469,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -1,417 +1,399 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import store from "../../store"; | 	import store from "../../store"; | ||||||
|   import { | 	import { | ||||||
|     GroupContactService, | 		GroupContactService, | ||||||
|     RunnerTeamService, | 		RunnerTeamService, | ||||||
|     RunnerOrganizationService, | 		RunnerOrganizationService, | ||||||
|   } from "@odit/lfk-client-js"; | 	} from "@odit/lfk-client-js"; | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; | 	import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   import isEmail from "validator/es/lib/isEmail"; | 	import isEmail from "validator/es/lib/isEmail"; | ||||||
|   import toast from "svelte-french-toast"; | 	import toast from "svelte-french-toast"; | ||||||
|   let data_loaded = false; | 	let data_loaded = false; | ||||||
|   let orgs = []; | 	let orgs = []; | ||||||
|   let teams = []; | 	let teams = []; | ||||||
|   export let params; | 	export let params; | ||||||
|   $: delete_triggered = false; | 	$: delete_triggered = false; | ||||||
|   $: original_data = {}; | 	$: original_data = {}; | ||||||
|   $: editable = {}; | 	$: editable = {}; | ||||||
|   $: changes_performed = !( | 	$: changes_performed = !( | ||||||
|     JSON.stringify(original_data) === JSON.stringify(editable) | 		JSON.stringify(original_data) === JSON.stringify(editable) | ||||||
|   ); | 	); | ||||||
|   $: isEmailValid = | 	$: isEmailValid = | ||||||
|     (editable.email || "") === "" || | 		(editable.email || "") === "" || | ||||||
|     (editable.email && isEmail(editable.email || "")); | 		(editable.email && isEmail(editable.email || "")); | ||||||
|   $: isFirstnameValid = editable.firstname !== ""; | 	$: isFirstnameValid = editable.firstname !== ""; | ||||||
|   $: isLastnameValid = editable.lastname !== ""; | 	$: isLastnameValid = editable.lastname !== ""; | ||||||
|   $: save_enabled = | 	$: save_enabled = | ||||||
|     changes_performed && | 		changes_performed && | ||||||
|     isFirstnameValid && | 		isFirstnameValid && | ||||||
|     isLastnameValid && | 		isLastnameValid && | ||||||
|     isEmailValid && | 		isEmailValid && | ||||||
|     isPhoneValidOrEmpty && | 		isPhoneValidOrEmpty && | ||||||
|     ((isAddress1Valid && iszipcodevalid && iscityvalid) || | 		((isAddress1Valid && iszipcodevalid && iscityvalid) || | ||||||
|       editable.address_checked === false); | 			editable.address_checked === false); | ||||||
|   const promise = GroupContactService.groupContactControllerGetOne( | 	const promise = GroupContactService.groupContactControllerGetOne( | ||||||
|     params.contact | 		params.contact | ||||||
|   ).then((data) => { | 	).then((data) => { | ||||||
|     data_loaded = true; | 		data_loaded = true; | ||||||
|     original_data = Object.assign(original_data, data); | 		original_data = Object.assign(original_data, data); | ||||||
|     editable = Object.assign(editable, original_data); | 		editable = Object.assign(editable, original_data); | ||||||
|     editable.groups = editable.groups.map((g) => g.id); | 		editable.groups = editable.groups.map((g) => g.id); | ||||||
|     original_data.groups = original_data.groups.map((g) => g.id); | 		original_data.groups = original_data.groups.map((g) => g.id); | ||||||
|     editable.address_checked = editable.address.address1 !== null; | 		editable.address_checked = editable.address.address1 !== null; | ||||||
|     original_data.address_checked = editable.address.address1 !== null; | 		original_data.address_checked = editable.address.address1 !== null; | ||||||
|     if (editable.address_checked === false) { | 		if (editable.address_checked === false) { | ||||||
|       editable.address = { | 			editable.address = { | ||||||
|         address1: "", | 				address1: "", | ||||||
|         address2: "", | 				address2: "", | ||||||
|         city: "", | 				city: "", | ||||||
|         postalcode: "", | 				postalcode: "", | ||||||
|         country: "", | 				country: "", | ||||||
|       }; | 			}; | ||||||
|     } | 		} | ||||||
|   }); | 	}); | ||||||
|   RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => { | 	RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => { | ||||||
|     orgs = val; | 		orgs = val; | ||||||
|   }); | 	}); | ||||||
|   RunnerTeamService.runnerTeamControllerGetAll().then((val) => { | 	RunnerTeamService.runnerTeamControllerGetAll().then((val) => { | ||||||
|     teams = val; | 		teams = val; | ||||||
|   }); | 	}); | ||||||
|   $: isPhoneValidOrEmpty = | 	$: isPhoneValidOrEmpty = | ||||||
|     editable.phone?.includes("+") || | 		editable.phone?.includes("+") || | ||||||
|     editable.phone === "" || | 		editable.phone === "" || | ||||||
|     editable.phone === null; | 		editable.phone === null; | ||||||
|   $: 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; | ||||||
|   function submit() { | 	function submit() { | ||||||
|     if (data_loaded === true && save_enabled) { | 		if (data_loaded === true && save_enabled) { | ||||||
|       toast.loading($_("contact-is-being-updated")); | 			toast.loading($_("contact-is-being-updated")); | ||||||
|       editable.address.country = "DE"; | 			editable.address.country = "DE"; | ||||||
|       if (editable.address_checked === false) { | 			if (editable.address_checked === false) { | ||||||
|         editable.address = null; | 				editable.address = null; | ||||||
|       } | 			} | ||||||
|       if (editable.email) editable.email = editable.email; | 			if (editable.email) editable.email = editable.email; | ||||||
|       if (editable.phone) editable.phone = editable.phone; | 			if (editable.phone) editable.phone = editable.phone; | ||||||
|       if (editable.middlename) editable.middlename = editable.middlename; | 			if (editable.middlename) editable.middlename = editable.middlename; | ||||||
|       GroupContactService.groupContactControllerPut(original_data.id, editable) | 			GroupContactService.groupContactControllerPut(original_data.id, editable) | ||||||
|         .then((resp) => { | 				.then((resp) => { | ||||||
|           Object.assign(original_data, editable); | 					Object.assign(original_data, editable); | ||||||
|           original_data = original_data; | 					original_data = original_data; | ||||||
|           toast.dismiss(); | 					toast.dismiss(); | ||||||
|           toast.success($_("updated-contact")); | 					toast.success($_("updated-contact")); | ||||||
|         }) | 				}) | ||||||
|         .catch((err) => {}); | 				.catch((err) => {}); | ||||||
|     } else { | 		} else { | ||||||
|     } | 		} | ||||||
|   } | 	} | ||||||
|   function deleteContact() { | 	function deleteContact() { | ||||||
|     GroupContactService.groupContactControllerRemove(original_data.id, true) | 		GroupContactService.groupContactControllerRemove(original_data.id, true) | ||||||
|       .then((resp) => { | 			.then((resp) => { | ||||||
|         location.replace("./"); | 				location.replace("./"); | ||||||
|       }) | 			}) | ||||||
|       .catch((err) => {}); | 			.catch((err) => {}); | ||||||
|   } | 	} | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#await promise} | {#await promise} | ||||||
|   {$_("loading-contact-details")} | 	{$_("loading-contact-details")} | ||||||
| {:then} | {:then} | ||||||
|   <section class="container p-5 select-none"> | 	<section class="container p-5 select-none"> | ||||||
|     <div class="flex flex-row mb-4"> | 		<div class="flex flex-row mb-4"> | ||||||
|       <div class="w-full"> | 			<div class="w-full"> | ||||||
|         <nav class="w-full flex"> | 				<nav class="w-full flex"> | ||||||
|           <ol class="list-none flex flex-row items-center justify-start"> | 					<ol class="list-none flex flex-row items-center justify-start"> | ||||||
|             <li class="flex items-center"> | 						<li class="flex items-center"> | ||||||
|               <svg | 							<a class="mr-2" href="./" | ||||||
|                 fill="currentColor" | 								><svg | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 									xmlns="http://www.w3.org/2000/svg" | ||||||
|                 viewBox="0 0 24 24" | 									width="24" | ||||||
|                 width="24" | 									height="24" | ||||||
|                 height="24" | 									viewBox="0 0 24 24" | ||||||
|                 ><path fill="none" d="M0 0h24v24H0z" /> | 									fill="none" | ||||||
|                 <path | 									stroke="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" | 									stroke-width="2" | ||||||
|                 /></svg | 									stroke-linecap="round" | ||||||
|               > | 									stroke-linejoin="round" | ||||||
|             </li> | 									class="inline-block" | ||||||
|             <li class="flex items-center ml-2"> | 									><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg | ||||||
|               <a class="mr-2" href="./">{$_("contacts")}</a><svg | 								> | ||||||
|                 stroke="currentColor" | 								{$_("contacts")}</a | ||||||
|                 fill="none" | 							> | ||||||
|                 stroke-width="2" | 						</li> | ||||||
|                 viewBox="0 0 24 24" | 					</ol> | ||||||
|                 stroke-linecap="round" | 				</nav> | ||||||
|                 stroke-linejoin="round" | 			</div> | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" | 		</div> | ||||||
|                 height="1em" | 		<div class="mb-4 text-3xl font-extrabold leading-tight"> | ||||||
|                 width="1em" | 			{original_data.firstname} | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 			{original_data.middlename || ""} | ||||||
|                 ><line x1="5" y1="12" x2="19" y2="12" /> | 			{original_data.lastname} | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg | 			<div data-id="contact_actions_${editable.id}"> | ||||||
|               > | 				{#if store.state.jwtinfo.userdetails.permissions.includes("CONTACT:DELETE")} | ||||||
|             </li> | 					{#if delete_triggered} | ||||||
|             <li class="flex items-center"> | 						<button | ||||||
|               <span class="mr-2" | 							on:click={deleteContact} | ||||||
|                 >{original_data.firstname} | 							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:w-auto sm:text-sm" | ||||||
|                 {original_data.middlename || ""} | 							>{$_("confirm-deletion")}</button | ||||||
|                 {original_data.lastname}</span | 						> | ||||||
|               > | 						<button | ||||||
|             </li> | 							on:click={() => { | ||||||
|           </ol> | 								delete_triggered = !delete_triggered; | ||||||
|         </nav> | 							}} | ||||||
|       </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" | ||||||
|     </div> | 							>{$_("cancel")}</button | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> | 						> | ||||||
|       {original_data.firstname} | 					{/if} | ||||||
|       {original_data.middlename || ""} | 					{#if !delete_triggered} | ||||||
|       {original_data.lastname} | 						<button | ||||||
|       <span data-id="contact_actions_${editable.id}"> | 							on:click={() => { | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("CONTACT:DELETE")} | 								delete_triggered = true; | ||||||
|           {#if delete_triggered} | 							}} | ||||||
|             <button | 							type="button" | ||||||
|               on:click={deleteContact} | 							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:w-auto sm:text-sm" | ||||||
|               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-contact")}</button | ||||||
|               >{$_("confirm-deletion")}</button | 						> | ||||||
|             > | 					{/if} | ||||||
|             <button | 				{/if} | ||||||
|               on:click={() => { | 				{#if !delete_triggered} | ||||||
|                 delete_triggered = !delete_triggered; | 					<button | ||||||
|               }} | 						disabled={!save_enabled} | ||||||
|               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" | 						class:opacity-50={!save_enabled} | ||||||
|               >{$_("cancel")}</button | 						type="button" | ||||||
|             > | 						on:click={submit} | ||||||
|           {/if} | 						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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|           {#if !delete_triggered} | 						>{$_("save-changes")}</button | ||||||
|             <button | 					> | ||||||
|               on:click={() => { | 				{/if} | ||||||
|                 delete_triggered = true; | 			</div> | ||||||
|               }} | 		</div> | ||||||
|               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" | 		<div class="text-sm w-full mt-2"> | ||||||
|               >{$_("delete-contact")}</button | 			<label for="firstname" class="font-semibold text-gray-700" | ||||||
|             > | 				>{$_("first-name")}</label | ||||||
|           {/if} | 			> | ||||||
|         {/if} | 			<input | ||||||
|         {#if !delete_triggered} | 				autocomplete="off" | ||||||
|           <button | 				placeholder={$_("first-name")} | ||||||
|             disabled={!save_enabled} | 				type="text" | ||||||
|             class:opacity-50={!save_enabled} | 				class:border-red-500={!isFirstnameValid} | ||||||
|             type="button" | 				class:focus:border-red-500={!isFirstnameValid} | ||||||
|             on:click={submit} | 				class:focus:ring-red-500={!isFirstnameValid} | ||||||
|             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" | 				bind:value={editable.firstname} | ||||||
|             >{$_("save-changes")}</button | 				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-neutral-800 rounded-md p-2" | ||||||
|         {/if} | 			/> | ||||||
|       </span> | 			{#if !isFirstnameValid} | ||||||
|     </div> | 				<span | ||||||
|     <!--  --> | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|     <div class="text-sm w-full"> | 				> | ||||||
|       <label for="firstname" class="font-medium text-gray-700" | 					{$_("first-name-is-required")} | ||||||
|         >{$_("first-name")}</label | 				</span> | ||||||
|       > | 			{/if} | ||||||
|       <input | 		</div> | ||||||
|         autocomplete="off" | 		<div class="text-sm w-full mt-2"> | ||||||
|         placeholder={$_("first-name")} | 			<label for="middlename" class="font-semibold text-gray-700" | ||||||
|         type="text" | 				>{$_("middle-name")}</label | ||||||
|         class:border-red-500={!isFirstnameValid} | 			> | ||||||
|         class:focus:border-red-500={!isFirstnameValid} | 			<input | ||||||
|         class:focus:ring-red-500={!isFirstnameValid} | 				autocomplete="off" | ||||||
|         bind:value={editable.firstname} | 				placeholder={$_("middle-name")} | ||||||
|         name="firstname" | 				type="text" | ||||||
|         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" | 				bind:value={editable.middlename} | ||||||
|       /> | 				name="middlename" | ||||||
|       {#if !isFirstnameValid} | 				class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|         <span | 			/> | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 		</div> | ||||||
|         > | 		<div class="text-sm w-full mt-2"> | ||||||
|           {$_("first-name-is-required")} | 			<label for="lastname" class="font-semibold text-gray-700" | ||||||
|         </span> | 				>{$_("last-name")}</label | ||||||
|       {/if} | 			> | ||||||
|     </div> | 			<input | ||||||
|     <div class="text-sm w-full"> | 				autocomplete="off" | ||||||
|       <label for="middlename" class="font-medium text-gray-700" | 				placeholder={$_("last-name")} | ||||||
|         >{$_("middle-name")}</label | 				type="text" | ||||||
|       > | 				bind:value={editable.lastname} | ||||||
|       <input | 				class:border-red-500={!isLastnameValid} | ||||||
|         autocomplete="off" | 				class:focus:border-red-500={!isLastnameValid} | ||||||
|         placeholder={$_("middle-name")} | 				class:focus:ring-red-500={!isLastnameValid} | ||||||
|         type="text" | 				name="lastname" | ||||||
|         bind:value={editable.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-neutral-800 rounded-md p-2" | ||||||
|         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" | 			{#if !isLastnameValid} | ||||||
|       /> | 				<span | ||||||
|     </div> | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|     <div class="text-sm w-full"> | 				> | ||||||
|       <label for="lastname" class="font-medium text-gray-700" | 					{$_("last-name-is-required")} | ||||||
|         >{$_("last-name")}</label | 				</span> | ||||||
|       > | 			{/if} | ||||||
|       <input | 		</div> | ||||||
|         autocomplete="off" | 		<div class="text-sm w-full mt-2"> | ||||||
|         placeholder={$_("last-name")} | 			<label for="email" class="font-semibold text-gray-700" | ||||||
|         type="text" | 				>{$_("e-mail-adress")}</label | ||||||
|         bind:value={editable.lastname} | 			> | ||||||
|         class:border-red-500={!isLastnameValid} | 			<input | ||||||
|         class:focus:border-red-500={!isLastnameValid} | 				autocomplete="off" | ||||||
|         class:focus:ring-red-500={!isLastnameValid} | 				placeholder={$_("e-mail-adress")} | ||||||
|         name="lastname" | 				type="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" | 				bind:value={editable.email} | ||||||
|       /> | 				class:border-red-500={!isEmailValid} | ||||||
|       {#if !isLastnameValid} | 				class:focus:border-red-500={!isEmailValid} | ||||||
|         <span | 				class:focus:ring-red-500={!isEmailValid} | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 				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-neutral-800 rounded-md p-2" | ||||||
|           {$_("last-name-is-required")} | 			/> | ||||||
|         </span> | 			{#if !isEmailValid} | ||||||
|       {/if} | 				<span | ||||||
|     </div> | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|     <div class="text-sm w-full"> | 				> | ||||||
|       <label for="email" class="font-medium text-gray-700" | 					{$_("valid-email-is-required")} | ||||||
|         >{$_("e-mail-adress")}</label | 				</span> | ||||||
|       > | 			{/if} | ||||||
|       <input | 		</div> | ||||||
|         autocomplete="off" | 		<div class="text-sm w-full mt-2"> | ||||||
|         placeholder={$_("e-mail-adress")} | 			<label for="phone" class="font-semibold text-gray-700">{$_("phone")}</label> | ||||||
|         type="email" | 			<input | ||||||
|         bind:value={editable.email} | 				autocomplete="off" | ||||||
|         class:border-red-500={!isEmailValid} | 				placeholder={$_("phone")} | ||||||
|         class:focus:border-red-500={!isEmailValid} | 				type="tel" | ||||||
|         class:focus:ring-red-500={!isEmailValid} | 				class:border-red-500={!isPhoneValidOrEmpty} | ||||||
|         name="email" | 				class:focus:border-red-500={!isPhoneValidOrEmpty} | ||||||
|         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:focus:ring-red-500={!isPhoneValidOrEmpty} | ||||||
|       /> | 				bind:value={editable.phone} | ||||||
|       {#if !isEmailValid} | 				name="phone" | ||||||
|         <span | 				class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 			/> | ||||||
|         > | 			{#if !isPhoneValidOrEmpty} | ||||||
|           {$_("valid-email-is-required")} | 				<span | ||||||
|         </span> | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|       {/if} | 				> | ||||||
|     </div> | 					{$_("valid-international-phone-number-is-required")} | ||||||
|     <div class="text-sm w-full"> | 				</span> | ||||||
|       <label for="phone" class="font-medium text-gray-700">{$_("phone")}</label> | 			{/if} | ||||||
|       <input | 		</div> | ||||||
|         autocomplete="off" | 		<div class="text-sm w-full mt-2"> | ||||||
|         placeholder={$_("phone")} | 			<span class="font-semibold text-gray-700">{$_("groups")}</span> | ||||||
|         type="tel" | 			<select | ||||||
|         class:border-red-500={!isPhoneValidOrEmpty} | 				bind:value={editable.groups} | ||||||
|         class:focus:border-red-500={!isPhoneValidOrEmpty} | 				name="team" | ||||||
|         class:focus:ring-red-500={!isPhoneValidOrEmpty} | 				multiple | ||||||
|         bind:value={editable.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-neutral-800 rounded-md p-2" | ||||||
|         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" | 				{#each teams as team} | ||||||
|       /> | 					<option value={team.id}> | ||||||
|       {#if !isPhoneValidOrEmpty} | 						{team.parentGroup.name} | ||||||
|         <span | 						> | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 						{team.name} | ||||||
|         > | 					</option> | ||||||
|           {$_("valid-international-phone-number-is-required")} | 				{/each} | ||||||
|         </span> | 				{#each orgs as org} | ||||||
|       {/if} | 					<option value={org.id}>{org.name}</option> | ||||||
|     </div> | 				{/each} | ||||||
|     <div class="text-sm w-full"> | 			</select> | ||||||
|       <span class="font-medium text-gray-700">{$_("groups")}</span> | 		</div> | ||||||
|       <select | 		<!--  --> | ||||||
|         bind:value={editable.groups} | 		<div class="flex items-start mt-2"> | ||||||
|         name="team" | 			<div class="flex items-center h-5"> | ||||||
|         multiple | 				<input | ||||||
|         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" | 					bind:checked={editable.address_checked} | ||||||
|       > | 					id="comments" | ||||||
|         {#each teams as team} | 					name="comments" | ||||||
|           <option value={team.id}> | 					type="checkbox" | ||||||
|             {team.parentGroup.name} | 					class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||||||
|             > | 				/> | ||||||
|             {team.name} | 			</div> | ||||||
|           </option> | 			<div class="ml-3 text-sm"> | ||||||
|         {/each} | 				<label for="comments" class="font-semibold text-gray-700" | ||||||
|         {#each orgs as org} | 					>{$_("address")}</label | ||||||
|           <option value={org.id}>{org.name}</option> | 				> | ||||||
|         {/each} | 			</div> | ||||||
|       </select> | 		</div> | ||||||
|     </div> | 		{#if editable.address_checked === true} | ||||||
|     <!--  --> | 			<div class="col-span-6"> | ||||||
|     <div class="flex items-start mt-2"> | 				<label for="address1" class="block text-sm font-medium text-gray-700" | ||||||
|       <div class="flex items-center h-5"> | 					>{$_("address")}</label | ||||||
|         <input | 				> | ||||||
|           bind:checked={editable.address_checked} | 				<input | ||||||
|           id="comments" | 					autocomplete="off" | ||||||
|           name="comments" | 					placeholder="Address" | ||||||
|           type="checkbox" | 					class:border-red-500={!isAddress1Valid} | ||||||
|           class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | 					class:focus:border-red-500={!isAddress1Valid} | ||||||
|         /> | 					class:focus:ring-red-500={!isAddress1Valid} | ||||||
|       </div> | 					bind:value={editable.address.address1} | ||||||
|       <div class="ml-3 text-sm"> | 					type="text" | ||||||
|         <label for="comments" class="font-medium text-gray-700" | 					name="address1" | ||||||
|           >{$_("address")}</label | 					class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|         > | 				/> | ||||||
|       </div> | 				{#if !isAddress1Valid} | ||||||
|     </div> | 					<span | ||||||
|     {#if editable.address_checked === true} | 						class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|       <div class="col-span-6"> | 					> | ||||||
|         <label for="address1" class="block text-sm font-medium text-gray-700" | 						{$_("address-is-required")} | ||||||
|           >{$_("address")}</label | 					</span> | ||||||
|         > | 				{/if} | ||||||
|         <input | 			</div> | ||||||
|           autocomplete="off" | 			<div class="col-span-6"> | ||||||
|           placeholder="Address" | 				<label for="address2" class="block text-sm font-medium text-gray-700" | ||||||
|           class:border-red-500={!isAddress1Valid} | 					>{$_("apartment-suite-etc")}</label | ||||||
|           class:focus:border-red-500={!isAddress1Valid} | 				> | ||||||
|           class:focus:ring-red-500={!isAddress1Valid} | 				<input | ||||||
|           bind:value={editable.address.address1} | 					autocomplete="off" | ||||||
|           type="text" | 					placeholder={$_("apartment-suite-etc")} | ||||||
|           name="address1" | 					bind:value={editable.address.address2} | ||||||
|           class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 					type="text" | ||||||
|         /> | 					name="address2" | ||||||
|         {#if !isAddress1Valid} | 					class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|           <span | 				/> | ||||||
|             class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 			</div> | ||||||
|           > | 			<div class="col-span-6"> | ||||||
|             {$_("address-is-required")} | 				<label for="zipcode" class="block text-sm font-medium text-gray-700" | ||||||
|           </span> | 					>{$_("zip-postal-code")}</label | ||||||
|         {/if} | 				> | ||||||
|       </div> | 				<input | ||||||
|       <div class="col-span-6"> | 					autocomplete="off" | ||||||
|         <label for="address2" class="block text-sm font-medium text-gray-700" | 					placeholder={$_("zip-postal-code")} | ||||||
|           >{$_("apartment-suite-etc")}</label | 					class:border-red-500={!iszipcodevalid} | ||||||
|         > | 					class:focus:border-red-500={!iszipcodevalid} | ||||||
|         <input | 					class:focus:ring-red-500={!iszipcodevalid} | ||||||
|           autocomplete="off" | 					bind:value={editable.address.postalcode} | ||||||
|           placeholder={$_("apartment-suite-etc")} | 					type="text" | ||||||
|           bind:value={editable.address.address2} | 					name="zipcode" | ||||||
|           type="text" | 					class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|           name="address2" | 				/> | ||||||
|           class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 				{#if !iszipcodevalid} | ||||||
|         /> | 					<span | ||||||
|       </div> | 						class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|       <div class="col-span-6"> | 					> | ||||||
|         <label for="zipcode" class="block text-sm font-medium text-gray-700" | 						{$_("valid-zipcode-postal-code-is-required")} | ||||||
|           >{$_("zip-postal-code")}</label | 					</span> | ||||||
|         > | 				{/if} | ||||||
|         <input | 			</div> | ||||||
|           autocomplete="off" | 			<div class="col-span-6"> | ||||||
|           placeholder={$_("zip-postal-code")} | 				<label for="city" class="block text-sm font-medium text-gray-700" | ||||||
|           class:border-red-500={!iszipcodevalid} | 					>{$_("city")}</label | ||||||
|           class:focus:border-red-500={!iszipcodevalid} | 				> | ||||||
|           class:focus:ring-red-500={!iszipcodevalid} | 				<input | ||||||
|           bind:value={editable.address.postalcode} | 					autocomplete="off" | ||||||
|           type="text" | 					placeholder={$_("city")} | ||||||
|           name="zipcode" | 					class:border-red-500={!iscityvalid} | ||||||
|           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:focus:border-red-500={!iscityvalid} | ||||||
|         /> | 					class:focus:ring-red-500={!iscityvalid} | ||||||
|         {#if !iszipcodevalid} | 					bind:value={editable.address.city} | ||||||
|           <span | 					type="text" | ||||||
|             class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 					name="city" | ||||||
|           > | 					class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|             {$_("valid-zipcode-postal-code-is-required")} | 				/> | ||||||
|           </span> | 				{#if !iscityvalid} | ||||||
|         {/if} | 					<span | ||||||
|       </div> | 						class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|       <div class="col-span-6"> | 					> | ||||||
|         <label for="city" class="block text-sm font-medium text-gray-700" | 						{$_("valid-city-is-required")} | ||||||
|           >{$_("city")}</label | 					</span> | ||||||
|         > | 				{/if} | ||||||
|         <input | 			</div> | ||||||
|           autocomplete="off" | 		{/if} | ||||||
|           placeholder={$_("city")} | 	</section> | ||||||
|           class:border-red-500={!iscityvalid} |  | ||||||
|           class:focus:border-red-500={!iscityvalid} |  | ||||||
|           class:focus:ring-red-500={!iscityvalid} |  | ||||||
|           bind:value={editable.address.city} |  | ||||||
|           type="text" |  | ||||||
|           name="city" |  | ||||||
|           class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |  | ||||||
|         /> |  | ||||||
|         {#if !iscityvalid} |  | ||||||
|           <span |  | ||||||
|             class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" |  | ||||||
|           > |  | ||||||
|             {$_("valid-city-is-required")} |  | ||||||
|           </span> |  | ||||||
|         {/if} |  | ||||||
|       </div> |  | ||||||
|     {/if} |  | ||||||
|   </section> |  | ||||||
| {:catch error} | {:catch error} | ||||||
|   <PromiseError {error} /> | 	<PromiseError {error} /> | ||||||
| {/await} | {/await} | ||||||
|   | |||||||
| @@ -8,20 +8,20 @@ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> |   <h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_("contacts")} |     {$_("contacts")} | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("CONTACT:CREATE")} |   </h4> | ||||||
|       <button |   {#if store.state.jwtinfo.userdetails.permissions.includes("CONTACT:CREATE")} | ||||||
|         on:click={() => { |     <button | ||||||
|           modal_open = true; |       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" |       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:w-auto sm:text-sm" | ||||||
|         {$_("create-a-new-contact")} |     > | ||||||
|       </button> |       {$_("create-a-new-contact")} | ||||||
|     {/if} |     </button> | ||||||
|   </span> |   {/if} | ||||||
|   <ContactsOverview bind:current_contacts /> |   <ContactsOverview bind:current_contacts /> | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,198 +1,198 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import { GroupContactService } from "@odit/lfk-client-js"; | 	import { GroupContactService } from "@odit/lfk-client-js"; | ||||||
|   const promise = GroupContactService.groupContactControllerGetAll().then( | 	const promise = GroupContactService.groupContactControllerGetAll().then( | ||||||
|     (result) => { | 		(result) => { | ||||||
|       current_contacts = result; | 			current_contacts = result; | ||||||
|     } | 		} | ||||||
|   ); | 	); | ||||||
|   import store from "../../store"; | 	import store from "../../store"; | ||||||
|   import ContactsEmptyState from "./ContactsEmptyState.svelte"; | 	import ContactsEmptyState from "./ContactsEmptyState.svelte"; | ||||||
|   import toast from "svelte-french-toast"; | 	import toast from "svelte-french-toast"; | ||||||
|   $: searchvalue = ""; | 	$: searchvalue = ""; | ||||||
|   $: active_deletes = []; | 	$: active_deletes = []; | ||||||
|   export let current_contacts = []; | 	export let current_contacts = []; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes("TEAM:GET")} | {#if store.state.jwtinfo.userdetails.permissions.includes("TEAM:GET")} | ||||||
|   {#await promise} | 	{#await promise} | ||||||
|     <div | 		<div | ||||||
|       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | 			class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|       role="alert" | 			role="alert" | ||||||
|     > | 		> | ||||||
|       <p class="font-bold">{$_("contacts-are-being-loaded")}</p> | 			<p class="font-bold">{$_("contacts-are-being-loaded")}</p> | ||||||
|       <p class="text-sm">{$_("this-might-take-a-moment")}</p> | 			<p class="text-sm">{$_("this-might-take-a-moment")}</p> | ||||||
|     </div> | 		</div> | ||||||
|   {:then} | 	{:then} | ||||||
|     {#if current_contacts.length === 0} | 		{#if current_contacts.length === 0} | ||||||
|       <ContactsEmptyState /> | 			<ContactsEmptyState /> | ||||||
|     {:else} | 		{:else} | ||||||
|       <input | 			<input | ||||||
|         type="search" | 				type="search" | ||||||
|         bind:value={searchvalue} | 				bind:value={searchvalue} | ||||||
|         placeholder={$_("datatable.search")} | 				placeholder={$_("datatable.search")} | ||||||
|         aria-label={$_("datatable.search")} | 				aria-label={$_("datatable.search")} | ||||||
|         class="mb-4" | 				class="mb-2 w-full sm:w-auto mt-1 sm:mt-0 p-2 rounded-md border" | ||||||
|       /> | 			/> | ||||||
|       <div | 			<div | ||||||
|         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll" | 				class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll" | ||||||
|       > | 			> | ||||||
|         <table class="divide-y divide-gray-200 w-full"> | 				<table class="divide-y divide-gray-200 w-full"> | ||||||
|           <thead class="bg-gray-50"> | 					<thead class="bg-gray-50"> | ||||||
|             <tr class="odd:bg-white even:bg-gray-100"> | 						<tr class="odd:bg-white even:bg-gray-100"> | ||||||
|               <th | 							<th | ||||||
|                 scope="col" | 								scope="col" | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | 								class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|               > | 							> | ||||||
|                 {$_("name")} | 								{$_("name")} | ||||||
|               </th> | 							</th> | ||||||
|               <th | 							<th | ||||||
|                 scope="col" | 								scope="col" | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | 								class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|               > | 							> | ||||||
|                 {$_("groups")} | 								{$_("groups")} | ||||||
|               </th> | 							</th> | ||||||
|               <th | 							<th | ||||||
|                 scope="col" | 								scope="col" | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | 								class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|               > | 							> | ||||||
|                 {$_("address")} | 								{$_("address")} | ||||||
|               </th> | 							</th> | ||||||
|               <th scope="col" class="relative px-6 py-3"> | 							<th scope="col" class="relative px-6 py-3"> | ||||||
|                 <span class="sr-only">{$_("action")}</span> | 								<span class="sr-only">{$_("action")}</span> | ||||||
|               </th> | 							</th> | ||||||
|             </tr> | 						</tr> | ||||||
|           </thead> | 					</thead> | ||||||
|           <tbody class="divide-y divide-gray-200"> | 					<tbody class="divide-y divide-gray-200"> | ||||||
|             {#each current_contacts as t} | 						{#each current_contacts as t} | ||||||
|               {#if Object.values(t) | 							{#if Object.values(t) | ||||||
|                 .toString() | 								.toString() | ||||||
|                 .toLowerCase() | 								.toLowerCase() | ||||||
|                 .includes(searchvalue)} | 								.includes(searchvalue)} | ||||||
|                 <tr | 								<tr | ||||||
|                   class="odd:bg-white even:bg-gray-100" | 									class="odd:bg-white even:bg-gray-100" | ||||||
|                   data-rowid="team_{t.id}" | 									data-rowid="team_{t.id}" | ||||||
|                 > | 								> | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> | 									<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                     <div class="flex items-center"> | 										<div class="flex items-center"> | ||||||
|                       <div class="ml-4"> | 											<div class="ml-4"> | ||||||
|                         <div class="text-sm font-medium text-gray-900"> | 												<div class="text-sm font-medium text-gray-900"> | ||||||
|                           {t.firstname} | 													{t.firstname} | ||||||
|                           {t.middlename || ""} | 													{t.middlename || ""} | ||||||
|                           {t.lastname} | 													{t.lastname} | ||||||
|                         </div> | 												</div> | ||||||
|                       </div> | 											</div> | ||||||
|                     </div> | 										</div> | ||||||
|                   </td> | 									</td> | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> | 									<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                     <div class="flex items-center"> | 										<div class="flex items-center"> | ||||||
|                       <div class="ml-4"> | 											<div | ||||||
|                         <div class="text-sm font-medium text-gray-900"> | 												class="text-sm font-medium text-gray-900 gap-0.5 flex flex-wrap" | ||||||
|                           {#if t.groups.length > 0} | 											> | ||||||
|                             {#each t.groups as g} | 												{#if t.groups.length > 0} | ||||||
|                               {#if g.responseType === "RUNNERORGANIZATION"} | 													{#each t.groups as g} | ||||||
|                                 <a | 														{#if g.responseType === "RUNNERORGANIZATION"} | ||||||
|                                   href="../orgs/{g.id}" | 															<a | ||||||
|                                   class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800" | 																href="../orgs/{g.id}" | ||||||
|                                   >{g.name}</a | 																class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current" | ||||||
|                                 > | 																>{g.name}</a | ||||||
|                               {:else} | 															> | ||||||
|                                 <a | 														{:else} | ||||||
|                                   href="../teams/{g.id}" | 															<a | ||||||
|                                   class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800" | 																href="../teams/{g.id}" | ||||||
|                                   >{g.parentGroup.name} | 																class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current" | ||||||
|                                   > | 																>{g.parentGroup.name} | ||||||
|                                   {g.name}</a | 																> | ||||||
|                                 > | 																{g.name}</a | ||||||
|                               {/if} | 															> | ||||||
|                             {/each} | 														{/if} | ||||||
|                           {:else} | 													{/each} | ||||||
|                             {$_("contact-is-not-a-member-in-any-group")} | 												{:else} | ||||||
|                           {/if} | 													{$_("contact-is-not-a-member-in-any-group")} | ||||||
|                         </div> | 												{/if} | ||||||
|                       </div> | 											</div> | ||||||
|                     </div> | 										</div> | ||||||
|                   </td> | 									</td> | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> | 									<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                     <div class="flex items-center"> | 										<div class="flex items-center"> | ||||||
|                       <div class="ml-4"> | 											<div class="ml-4"> | ||||||
|                         <div class="text-sm font-medium text-gray-900"> | 												<div class="text-sm font-medium text-gray-900"> | ||||||
|                           {#if t.address.address1 !== null} | 													{#if t.address.address1 !== null} | ||||||
|                             {t.address.address1}<br /> | 														{t.address.address1}<br /> | ||||||
|                             {t.address.address2 || ""}<br /> | 														{t.address.address2 || ""}<br /> | ||||||
|                             {t.address.postalcode} | 														{t.address.postalcode} | ||||||
|                             {t.address.city} | 														{t.address.city} | ||||||
|                             {t.address.country} | 														{t.address.country} | ||||||
|                           {/if} | 													{/if} | ||||||
|                         </div> | 												</div> | ||||||
|                       </div> | 											</div> | ||||||
|                     </div> | 										</div> | ||||||
|                   </td> | 									</td> | ||||||
|                   {#if active_deletes[t.id] === true} | 									{#if active_deletes[t.id] === true} | ||||||
|                     <td | 										<td | ||||||
|                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium" | 											class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium" | ||||||
|                     > | 										> | ||||||
|                       <button | 											<button | ||||||
|                         on:click={() => { | 												on:click={() => { | ||||||
|                           active_deletes[t.id] = false; | 													active_deletes[t.id] = false; | ||||||
|                         }} | 												}} | ||||||
|                         tabindex="0" | 												tabindex="0" | ||||||
|                         class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer" | 												class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer" | ||||||
|                         >{$_("cancel-delete")}</button | 												>{$_("cancel-delete")}</button | ||||||
|                       > | 											> | ||||||
|                       <button | 											<button | ||||||
|                         on:click={() => { | 												on:click={() => { | ||||||
|                           toast.loading($_("deleting-contact")); | 													toast.loading($_("deleting-contact")); | ||||||
|                           GroupContactService.groupContactControllerRemove( | 													GroupContactService.groupContactControllerRemove( | ||||||
|                             t.id, | 														t.id, | ||||||
|                             false | 														false | ||||||
|                           ).then((resp) => { | 													).then((resp) => { | ||||||
|                             current_contacts = current_contacts.filter( | 														current_contacts = current_contacts.filter( | ||||||
|                               (obj) => obj.id !== t.id | 															(obj) => obj.id !== t.id | ||||||
|                             ); | 														); | ||||||
|                             toast.dismiss(); | 														toast.dismiss(); | ||||||
|                             toast($_("contact-deleted")); | 														toast.success($_("contact-deleted")); | ||||||
|                           }); | 													}); | ||||||
|                         }} | 												}} | ||||||
|                         tabindex="0" | 												tabindex="0" | ||||||
|                         class="ml-4 text-red-600 hover:text-red-900 cursor-pointer" | 												class="ml-4 text-red-600 hover:text-red-900 cursor-pointer" | ||||||
|                         >{$_("confirm-delete")}</button | 												>{$_("confirm-delete")}</button | ||||||
|                       > | 											> | ||||||
|                     </td> | 										</td> | ||||||
|                   {:else} | 									{:else} | ||||||
|                     <td | 										<td | ||||||
|                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium" | 											class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium" | ||||||
|                     > | 										> | ||||||
|                       <a | 											<a | ||||||
|                         href="./{t.id}" | 												href="./{t.id}" | ||||||
|                         class="text-indigo-600 hover:text-indigo-900" | 												class="text-indigo-600 hover:text-indigo-900" | ||||||
|                         >{$_("details")}</a | 												>{$_("details")}</a | ||||||
|                       > | 											> | ||||||
|                       {#if store.state.jwtinfo.userdetails.permissions.includes("TEAM:DELETE")} | 											{#if store.state.jwtinfo.userdetails.permissions.includes("TEAM:DELETE")} | ||||||
|                         <button | 												<button | ||||||
|                           on:click={() => { | 													on:click={() => { | ||||||
|                             active_deletes[t.id] = true; | 														active_deletes[t.id] = true; | ||||||
|                           }} | 													}} | ||||||
|                           tabindex="0" | 													tabindex="0" | ||||||
|                           class="ml-4 text-red-600 hover:text-red-900 cursor-pointer" | 													class="ml-4 text-red-600 hover:text-red-900 cursor-pointer" | ||||||
|                           >{$_("delete")}</button | 													>{$_("delete")}</button | ||||||
|                         > | 												> | ||||||
|                       {/if} | 											{/if} | ||||||
|                     </td> | 										</td> | ||||||
|                   {/if} | 									{/if} | ||||||
|                 </tr> | 								</tr> | ||||||
|               {/if} | 							{/if} | ||||||
|             {/each} | 						{/each} | ||||||
|           </tbody> | 					</tbody> | ||||||
|         </table> | 				</table> | ||||||
|       </div> | 			</div> | ||||||
|     {/if} | 		{/if} | ||||||
|   {:catch error} | 	{:catch error} | ||||||
|     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> | 		<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"> | 			<span class="inline-block align-middle mr-8"> | ||||||
|         <b class="capitalize">{$_("general_promise_error")}</b> | 				<b class="capitalize">{$_("general_promise_error")}</b> | ||||||
|         {error} | 				{error} | ||||||
|       </span> | 			</span> | ||||||
|     </div> | 		</div> | ||||||
|   {/await} | 	{/await} | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -1,431 +1,459 @@ | |||||||
| <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"; | ||||||
|   import { Toaster } from "svelte-french-toast"; | 	import { Toaster } from "svelte-french-toast"; | ||||||
|   $: 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"> | ||||||
|   <div | 	<div | ||||||
|     class:collapsed_navigation={!navOpen} | 		class:collapsed_navigation={!navOpen} | ||||||
|     class="select-none fixed top-0 left-0 z-20 h-full pb-10 overflow-x-hidden overflow-y-auto transition origin-left transform border-r w-60 bg-gray-50" | 		style="z-index:11;" | ||||||
|   > | 		class="select-none fixed top-0 left-0 h-full pb-10 overflow-x-hidden overflow-y-auto transition origin-left transform border-r w-60 bg-gray-50" | ||||||
|     <a href="/" class="flex items-center px-4 py-5"> | 	> | ||||||
|       <img src="/lfk-logo.png" alt="Logo" class="h-10" /> | 		<a href="/" class="flex items-center px-4 py-5"> | ||||||
|       <h3 class="text-lg font-bold">LfK!Admin</h3> | 			<img src="/lfk-logo.png" alt="Logo" class="h-10" /> | ||||||
|     </a> | 			<h3 class="text-lg font-bold">LfK!Admin</h3> | ||||||
|     <nav class="text-sm font-medium text-gray-600" aria-label="Main Navigation"> | 		</a> | ||||||
|       <a | 		<nav class="text-sm font-medium text-gray-600" aria-label="Main Navigation"> | ||||||
|         class:bg-gray-100={$router.path === "/"} | 			<a | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | 				class:activenav={$router.path === "/"} | ||||||
|         href="/" | 				class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||||
|       > | 				href="/" | ||||||
|         <svg | 			> | ||||||
|           class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | 				<svg | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 					class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600" | ||||||
|           viewBox="0 0 20 20" | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|           fill="currentColor" | 					viewBox="0 0 20 20" | ||||||
|         > | 					fill="currentColor" | ||||||
|           <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" | 					<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" | ||||||
|         </svg> | 					/> | ||||||
|         <span>{$_("dashboard-title")}</span> | 				</svg> | ||||||
|       </a> | 				<span>{$_("dashboard-title")}</span> | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("ORGANIZATION:GET")} | 			</a> | ||||||
|         <a | 			{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:GET") && store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")} | ||||||
|           class:bg-gray-100={$router.path.includes("/orgs/")} | 				<a | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | 					class:activenav={$router.path.includes("/cardassignment/")} | ||||||
|           href="/orgs/" | 					class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||||
|         > | 					href="/cardassignment/" | ||||||
|           <svg | 				> | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | 					<svg | ||||||
|             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" | 						fill="currentColor" | ||||||
|             width="24" | 						class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600" | ||||||
|             height="24" | 					> | ||||||
|             ><path fill="none" d="M0 0h24v24H0z" /> | 						<path | ||||||
|             <path | 							fill-rule="evenodd" | ||||||
|               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" | 							d="M14.615 1.595a.75.75 0 0 1 .359.852L12.982 9.75h7.268a.75.75 0 0 1 .548 1.262l-10.5 11.25a.75.75 0 0 1-1.272-.71l1.992-7.302H3.75a.75.75 0 0 1-.548-1.262l10.5-11.25a.75.75 0 0 1 .913-.143Z" | ||||||
|             /></svg | 							clip-rule="evenodd" | ||||||
|           > | 						/> | ||||||
|           <span>{$_("orgs")}</span> | 					</svg> | ||||||
|         </a> |  | ||||||
|       {/if} | 					<span>{$_('card_assignment_menu')}</span> | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("USER:GET")} | 				</a> | ||||||
|         <a | 				<a | ||||||
|           class:bg-gray-100={$router.path === "/users/"} | 					class:activenav={$router.path.includes("/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-200 hover:text-gray-900 w-full font-semibold" | ||||||
|           href="/users/" | 					href="/runners/" | ||||||
|         > | 				> | ||||||
|           <svg | 					<svg | ||||||
|             xmlns="http://www.w3.org/2000/svg" | 						xmlns="http://www.w3.org/2000/svg" | ||||||
|             width="24" | 						viewBox="0 0 24 24" | ||||||
|             height="24" | 						class="flex-shrink-0 w-5 h-5 mr-2 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" | ||||||
|             viewBox="0 0 24 24" | 						height="24" | ||||||
|             ><path fill="none" d="M0 0h24v24H0z" /> | 						><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" | 							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 | 						/></svg | ||||||
|           > | 					> | ||||||
|           <span>{$_("users")}</span> | 					<span>{$_("runners")}</span> | ||||||
|         </a> | 				</a> | ||||||
|       {/if} | 			{/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("USERGROUP:GET")} | 			{#if store.state.jwtinfo.userdetails.permissions.includes("TEAM:GET")} | ||||||
|         <a | 				<a | ||||||
|           class:bg-gray-100={$router.path === "/groups/"} | 					class:activenav={$router.path.includes("/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-200 hover:text-gray-900 w-full font-semibold" | ||||||
|           href="/groups/" | 					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 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" | 						viewBox="0 0 640 512" | ||||||
|             ><path | 						><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" | 							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 | 						/></svg | ||||||
|           > | 					> | ||||||
|           <span>{$_("user-groups")}</span> | 					<span>{$_("teams")}</span> | ||||||
|         </a> | 				</a> | ||||||
|       {/if} | 			{/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:GET")} | 			{#if store.state.jwtinfo.userdetails.permissions.includes("ORGANIZATION:GET")} | ||||||
|         <a | 				<a | ||||||
|           class:bg-gray-100={$router.path === "/runners/"} | 					class:activenav={$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-200 hover:text-gray-900 w-full font-semibold" | ||||||
|           href="/runners/" | 					href="/orgs/" | ||||||
|         > | 				> | ||||||
|           <svg | 					<svg | ||||||
|             xmlns="http://www.w3.org/2000/svg" | 						class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600" | ||||||
|             viewBox="0 0 24 24" | 						fill="currentColor" | ||||||
|             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" /> | 						><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" | 							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 | 						/></svg | ||||||
|           > | 					> | ||||||
|           <span>{$_("runners")}</span> | 					<span>{$_("orgs")}</span> | ||||||
|         </a> | 				</a> | ||||||
|       {/if} | 			{/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("TEAM:GET")} | 			{#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:GET")} | ||||||
|         <a | 				<a | ||||||
|           class:bg-gray-100={$router.path === "/teams/"} | 					class:activenav={$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-200 hover:text-gray-900 w-full font-semibold" | ||||||
|           href="/teams/" | 					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 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" | 						fill="currentColor" | ||||||
|             width="24" | 						xmlns="http://www.w3.org/2000/svg" | ||||||
|             height="24" | 						viewBox="0 0 24 24" | ||||||
|             xmlns="http://www.w3.org/2000/svg" | 						width="24" | ||||||
|             viewBox="0 0 640 512" | 						height="24" | ||||||
|             ><path | 						><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|               fill="currentColor" | 						<path | ||||||
|               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" | 							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 | 						/></svg | ||||||
|           > | 					> | ||||||
|           <span>{$_("teams")}</span> | 					<span>{$_("donors")}</span> | ||||||
|         </a> | 				</a> | ||||||
|       {/if} | 			{/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:GET")} | 			{#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:GET")} | ||||||
|         <a | 				<a | ||||||
|           class:bg-gray-100={$router.path.includes("/donors/")} | 					class:activenav={$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-200 hover:text-gray-900 w-full font-semibold" | ||||||
|           href="/donors/" | 					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 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" | 						height="24" | ||||||
|             ><path fill="none" d="M0 0h24v24H0z" /> | 						><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" | 							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 | 						/></svg | ||||||
|           > | 					> | ||||||
|           <span>{$_("donors")}</span> | 					<span>{$_("donations")}</span> | ||||||
|         </a> | 				</a> | ||||||
|       {/if} | 			{/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:GET")} | 			{#if store.state.jwtinfo.userdetails.permissions.includes("TRACK:GET")} | ||||||
|         <a | 				<a | ||||||
|           class:bg-gray-100={$router.path.includes("/donations/")} | 					class:activenav={$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-200 hover:text-gray-900 w-full font-semibold" | ||||||
|           href="/donations/" | 					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 transition group-hover:text-gray-600" | ||||||
|             fill="currentColor" | 						fill="currentColor" | ||||||
|             xmlns="http://www.w3.org/2000/svg" | 						width="24" | ||||||
|             viewBox="0 0 24 24" | 						height="24" | ||||||
|             width="24" | 						xmlns="http://www.w3.org/2000/svg" | ||||||
|             height="24" | 						viewBox="0 0 640 512" | ||||||
|             ><path fill="none" d="M0 0h24v24H0z" /> | 						><path | ||||||
|             <path | 							fill="currentColor" | ||||||
|               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" | 							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 | 						/></svg | ||||||
|           > | 					> | ||||||
|           <span>{$_("donations")}</span> | 					<span>{$_("tracks")}</span> | ||||||
|         </a> | 				</a> | ||||||
|       {/if} | 			{/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("TRACK:GET")} | 			{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")} | ||||||
|         <a | 				<a | ||||||
|           class:bg-gray-100={$router.path === "/tracks/"} | 					class:activenav={$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-200 hover:text-gray-900 w-full font-semibold" | ||||||
|           href="/tracks/" | 					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 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" | 						viewBox="0 0 24 24" | ||||||
|             ><path | 					> | ||||||
|               fill="currentColor" | 						<path fill="none" d="M0 0h24v24H0z" /> | ||||||
|               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" | 						<path | ||||||
|             /></svg | 							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" | ||||||
|           <span>{$_("tracks")}</span> | 						/></svg | ||||||
|         </a> | 					> | ||||||
|       {/if} | 					<span>{$_("cards")}</span> | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")} | 				</a> | ||||||
|         <a | 			{/if} | ||||||
|           class:bg-gray-100={$router.path === "/cards/"} | 			{#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:GET")} | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | 				<a | ||||||
|           href="/cards/" | 					class:activenav={$router.path.includes("/scans/")} | ||||||
|         > | 					class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||||
|           <svg | 					href="/scans/" | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | 				> | ||||||
|             fill="currentColor" | 					<svg | ||||||
|             width="24" | 						class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600" | ||||||
|             height="24" | 						fill="currentColor" | ||||||
|             xmlns="http://www.w3.org/2000/svg" | 						width="24" | ||||||
|             viewBox="0 0 24 24" | 						height="24" | ||||||
|           > | 						xmlns="http://www.w3.org/2000/svg" | ||||||
|             <path fill="none" d="M0 0h24v24H0z" /> | 						viewBox="0 0 24 24" | ||||||
|             <path | 						><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|               fill="currentColor" | 						<path | ||||||
|               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" | 							fill="currentColor" | ||||||
|             /></svg | 							d="M2 4h2v16H2V4zm4 0h1v16H6V4zm2 0h2v16H8V4zm3 0h2v16h-2V4zm3 0h2v16h-2V4zm3 0h1v16h-1V4zm2 0h3v16h-3V4z" | ||||||
|           > | 						/></svg | ||||||
|           <span>{$_("cards")}</span> | 					> | ||||||
|         </a> | 					<span>Scans</span> | ||||||
|       {/if} | 				</a> | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:GET")} | 			{/if} | ||||||
|         <a | 			{#if store.state.jwtinfo.userdetails.permissions.includes("CONTACT:GET")} | ||||||
|           class:bg-gray-100={$router.path === "/scans/"} | 				<a | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | 					class:activenav={$router.path.includes("/contacts/")} | ||||||
|           href="/scans/" | 					class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||||
|         > | 					href="/contacts/" | ||||||
|           <svg | 				> | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | 					<svg | ||||||
|             fill="currentColor" | 						fill="currentColor" | ||||||
|             width="24" | 						class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600" | ||||||
|             height="24" | 						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" | ||||||
|             ><path fill="none" d="M0 0h24v24H0z" /> | 						height="24" | ||||||
|             <path | 						><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|               fill="currentColor" | 						<path | ||||||
|               d="M2 4h2v16H2V4zm4 0h1v16H6V4zm2 0h2v16H8V4zm3 0h2v16h-2V4zm3 0h2v16h-2V4zm3 0h1v16h-1V4zm2 0h3v16h-3V4z" | 							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 | 						/></svg | ||||||
|           > | 					> | ||||||
|           <span>Scans</span> | 					<span>{$_("contacts")}</span> | ||||||
|         </a> | 				</a> | ||||||
|       {/if} | 			{/if} | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("CONTACT:GET")} | 			{#if store.state.jwtinfo.userdetails.permissions.includes("STATION:GET")} | ||||||
|         <a | 				<a | ||||||
|           class:bg-gray-100={$router.path === "/contacts/"} | 					class:activenav={$router.path.includes("/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-200 hover:text-gray-900 w-full font-semibold" | ||||||
|           href="/contacts/" | 					href="/scanstations/" | ||||||
|         > | 				> | ||||||
|           <svg | 					<svg | ||||||
|             fill="currentColor" | 						class="flex-shrink-0 w-5 h-5 mr-2 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" | ||||||
|             viewBox="0 0 24 24" | 						height="24" | ||||||
|             width="24" | 						viewBox="0 0 24 24" | ||||||
|             height="24" | 						xmlns="http://www.w3.org/2000/svg" | ||||||
|             ><path fill="none" d="M0 0h24v24H0z" /> | 						><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|             <path | 						<path | ||||||
|               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" | 							fill="currentColor" | ||||||
|             /></svg | 							d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" | ||||||
|           > | 						/></svg | ||||||
|           <span>{$_("contacts")}</span> | 					> | ||||||
|         </a> | 					<span>{$_("scanstations")}</span> | ||||||
|       {/if} | 				</a> | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("STATION:GET")} | 			{/if} | ||||||
|         <a | 			{#if store.state.jwtinfo.userdetails.permissions.includes("STATSCLIENT:GET")} | ||||||
|           class:bg-gray-100={$router.path === "/scanstations/"} | 				<a | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | 					class:activenav={$router.path.includes("/statsclients/")} | ||||||
|           href="/scanstations/" | 					class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||||
|         > | 					href="/statsclients/" | ||||||
|           <svg | 				> | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | 					<svg | ||||||
|             fill="currentColor" | 						class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600" | ||||||
|             width="24" | 						fill="currentColor" | ||||||
|             height="24" | 						width="24" | ||||||
|             viewBox="0 0 24 24" | 						height="24" | ||||||
|             xmlns="http://www.w3.org/2000/svg" | 						viewBox="0 0 24 24" | ||||||
|             ><path fill="none" d="M0 0h24v24H0z" /> | 						xmlns="http://www.w3.org/2000/svg" | ||||||
|             <path | 						><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|               fill="currentColor" | 						<path | ||||||
|               d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" | 							fill="currentColor" | ||||||
|             /></svg | 							d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" | ||||||
|           > | 						/></svg | ||||||
|           <span>{$_("scanstations")}</span> | 					> | ||||||
|         </a> | 					<span>{$_("statsclients")}</span> | ||||||
|       {/if} | 				</a> | ||||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("STATSCLIENT:GET")} | 			{/if} | ||||||
|         <a | 			{#if store.state.jwtinfo.userdetails.permissions.includes("USER:GET")} | ||||||
|           class:bg-gray-100={$router.path === "/statsclients/"} | 				<a | ||||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | 					class:activenav={$router.path.includes("/users/")} | ||||||
|           href="/statsclients/" | 					class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||||
|         > | 					href="/users/" | ||||||
|           <svg | 				> | ||||||
|             class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | 					<svg | ||||||
|             fill="currentColor" | 						xmlns="http://www.w3.org/2000/svg" | ||||||
|             width="24" | 						width="24" | ||||||
|             height="24" | 						height="24" | ||||||
|             viewBox="0 0 24 24" | 						class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600" | ||||||
|             xmlns="http://www.w3.org/2000/svg" | 						fill="currentColor" | ||||||
|             ><path fill="none" d="M0 0h24v24H0z" /> | 						viewBox="0 0 24 24" | ||||||
|             <path | 						><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|               fill="currentColor" | 						<path | ||||||
|               d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" | 							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 | 						/></svg | ||||||
|           > | 					> | ||||||
|           <span>{$_("statsclients")}</span> | 					<span>{$_("users")}</span> | ||||||
|         </a> | 				</a> | ||||||
|       {/if} | 			{/if} | ||||||
|       <a | 			{#if store.state.jwtinfo.userdetails.permissions.includes("USERGROUP:GET")} | ||||||
|         class:bg-gray-100={$router.path === "/settings/"} | 				<a | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | 					class:activenav={$router.path.includes("/groups/")} | ||||||
|         href="/settings/" | 					class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||||
|       > | 					href="/groups/" | ||||||
|         <svg | 				> | ||||||
|           class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600" | 					<svg | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 						class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600" | ||||||
|           viewBox="0 0 20 20" | 						fill="currentColor" | ||||||
|           fill="currentColor" | 						width="24" | ||||||
|         > | 						height="24" | ||||||
|           <path | 						xmlns="http://www.w3.org/2000/svg" | ||||||
|             fill-rule="evenodd" | 						viewBox="0 0 640 512" | ||||||
|             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" | 						><path | ||||||
|             clip-rule="evenodd" | 							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> | 						/></svg | ||||||
|         <span>{$_("settings")}</span> | 					> | ||||||
|       </a> | 					<span>{$_("user-groups")}</span> | ||||||
|       <a | 				</a> | ||||||
|         class:bg-gray-100={$router.path === "/about/"} | 			{/if} | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | 			<a | ||||||
|         href="/about/" | 				class:activenav={$router.path === "/settings/"} | ||||||
|       > | 				class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||||
|         <svg | 				href="/settings/" | ||||||
|           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" | 				<svg | ||||||
|           fill="none" | 					class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600" | ||||||
|           stroke="currentColor" | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|           stroke-width="2" | 					viewBox="0 0 20 20" | ||||||
|           stroke-linecap="round" | 					fill="currentColor" | ||||||
|           stroke-linejoin="round" | 				> | ||||||
|           viewBox="0 0 24 24" | 					<path | ||||||
|           ><circle cx="12" cy="12" r="10" /> | 						fill-rule="evenodd" | ||||||
|           <path d="M12 16v-4M12 8h.01" /></svg | 						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" | ||||||
|         > | 						clip-rule="evenodd" | ||||||
|         <span>{$_("about")}</span> | 					/> | ||||||
|       </a> | 				</svg> | ||||||
|       <button | 				<span>{$_("settings")}</span> | ||||||
|         tabindex="0" | 			</a> | ||||||
|         class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" | 			<a | ||||||
|         on:click={() => { | 				class:activenav={$router.path === "/about/"} | ||||||
|           AuthService.authControllerLogout(); | 				class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||||
|           logout(); | 				href="/about/" | ||||||
|         }} | 			> | ||||||
|       > | 				<svg | ||||||
|         <svg | 					class="flex-shrink-0 w-5 h-5 mr-2 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" | 					fill="none" | ||||||
|           width="24" | 					stroke="currentColor" | ||||||
|           height="24" | 					stroke-width="2" | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 					stroke-linecap="round" | ||||||
|           viewBox="0 0 24 24" | 					stroke-linejoin="round" | ||||||
|           ><path fill="none" d="M0 0h24v24H0z" /> | 					viewBox="0 0 24 24" | ||||||
|           <path | 					><circle cx="12" cy="12" r="10" /> | ||||||
|             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" | 					<path d="M12 16v-4M12 8h.01" /></svg | ||||||
|           /></svg | 				> | ||||||
|         > | 				<span>{$_("about")}</span> | ||||||
|         <span>{$_("logout")}</span> | 			</a> | ||||||
|       </button> | 			<button | ||||||
|     </nav> | 				tabindex="0" | ||||||
|   </div> | 				class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||||
|   <div class="ml-0 transition md:ml-60"> | 				on:click={() => { | ||||||
|     <header | 					AuthService.authControllerLogout(); | ||||||
|       class="flex items-center justify-between w-full px-4 bg-white border-b h-14 md:hidden" | 					logout(); | ||||||
|     > | 				}} | ||||||
|       <button | 			> | ||||||
|         on:click={() => { | 				<svg | ||||||
|           navOpen = true; | 					class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600" | ||||||
|         }} | 					fill="currentColor" | ||||||
|         class="block btn btn-light md:hidden" | 					width="24" | ||||||
|       > | 					height="24" | ||||||
|         <span class="sr-only">Menu</span><svg | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|           class="w-4 h-4" | 					viewBox="0 0 24 24" | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 					><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|           viewBox="0 0 20 20" | 					<path | ||||||
|           fill="currentcolor" | 						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" | ||||||
|           ><path | 					/></svg | ||||||
|             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" | 				<span>{$_("logout")}</span> | ||||||
|             clip-rule="evenodd" | 			</button> | ||||||
|           /></svg | 		</nav> | ||||||
|         ></button | 	</div> | ||||||
|       > | 	<div class="ml-0 transition md:ml-60"> | ||||||
|     </header> | 		<header | ||||||
|     <Toaster position="top-right" /> | 			class="flex items-center w-full px-4 bg-white border-b h-14 md:hidden" | ||||||
|     <slot> | 		> | ||||||
|       <NoComponentLoaded /> | 			<button | ||||||
|     </slot> | 				on:click={() => { | ||||||
|   </div> | 					navOpen = true; | ||||||
|   {#if navOpen === true} | 				}} | ||||||
|     <button | 				class="block btn btn-light md:hidden" | ||||||
|       on:click={() => { | 			> | ||||||
|         navOpen = false; | 				<span class="sr-only">Menu</span><svg | ||||||
|       }} | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|       class:hidden={!navOpen} | 					fill="none" | ||||||
|       class="fixed inset-0 z-10 w-screen h-screen bg-black bg-opacity-25 md:hidden" | 					viewBox="0 0 24 24" | ||||||
|     /> | 					stroke-width="1.5" | ||||||
|   {/if} | 					stroke="currentColor" | ||||||
|  | 					class="size-6" | ||||||
|  | 				> | ||||||
|  | 					<path | ||||||
|  | 						stroke-linecap="round" | ||||||
|  | 						stroke-linejoin="round" | ||||||
|  | 						d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" | ||||||
|  | 					/> | ||||||
|  | 				</svg> | ||||||
|  | 			</button> | ||||||
|  | 			<span class="inline-block"> | ||||||
|  | 				<img src="/lfk-logo.png" alt="Logo" class="h-8 inline-block" /> | ||||||
|  | 				<span class="text-lg font-bold">LfK!Admin</span> | ||||||
|  | 			</span> | ||||||
|  | 		</header> | ||||||
|  | 		<Toaster position="top-right" /> | ||||||
|  | 		<slot> | ||||||
|  | 			<NoComponentLoaded /> | ||||||
|  | 		</slot> | ||||||
|  | 	</div> | ||||||
|  | 	{#if navOpen === true} | ||||||
|  | 		<button | ||||||
|  | 			on:click={() => { | ||||||
|  | 				navOpen = false; | ||||||
|  | 			}} | ||||||
|  | 			class:hidden={!navOpen} | ||||||
|  | 			class="fixed inset-0 z-10 w-screen h-screen bg-black bg-opacity-25 md:hidden" | ||||||
|  | 		/> | ||||||
|  | 	{/if} | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
| <style> | <style> | ||||||
|   .collapsed_navigation { | 	.collapsed_navigation { | ||||||
|     transform: translateX(-100%); | 		transform: translateX(-100%); | ||||||
|   } | 	} | ||||||
|   @media (min-width: 768px) { | 	@media (min-width: 768px) { | ||||||
|     .collapsed_navigation { | 		.collapsed_navigation { | ||||||
|       transform: translateX(0px); | 			transform: translateX(0px); | ||||||
|     } | 		} | ||||||
|   } | 	} | ||||||
| </style> | </style> | ||||||
|   | |||||||
| @@ -1,230 +1,263 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import { StatsService } from "@odit/lfk-client-js"; | 	import { StatsService } from "@odit/lfk-client-js"; | ||||||
|   import store from "../../store"; | 	import store from "../../store"; | ||||||
|   import StatCard from "./StatCard.svelte"; | 	import StatCard from "./StatCard.svelte"; | ||||||
|   let navOpen = false; | 	const stats_promise = StatsService.statsControllerGet(); | ||||||
|   const stats_promise = StatsService.statsControllerGet(); |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <div class="p-2 md:p-5 overflow-x-hidden"> | <div class="p-2 md:p-5 overflow-x-hidden"> | ||||||
|   <h1 class="text-3xl leading-tight mb-4"> | 	<h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_("dashboard-greeting")}, | 		{$_("dashboard-greeting")} | ||||||
|     <span class="text-blue-500" | 		<span class="text-blue-500" | ||||||
|       >{store.state.jwtinfo.userdetails.firstname} | 			>{store.state.jwtinfo.userdetails.firstname} | ||||||
|       {store.state.jwtinfo.userdetails.lastname}</span | 			{store.state.jwtinfo.userdetails.lastname}</span | ||||||
|     > | 		> | ||||||
|   </h1> | 	</h4> | ||||||
|   {#await stats_promise} | 	{#await stats_promise} | ||||||
|     <div | 		<div | ||||||
|       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | 			class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|       role="alert" | 			role="alert" | ||||||
|     > | 		> | ||||||
|       <p class="font-bold">{$_("stats-are-being-loaded")}</p> | 			<p class="font-bold">{$_("stats-are-being-loaded")}</p> | ||||||
|       <p class="text-sm">{$_("this-might-take-a-moment")}</p> | 			<p class="text-sm">{$_("this-might-take-a-moment")}</p> | ||||||
|     </div> | 		</div> | ||||||
|   {:then stats} | 	{:then stats} | ||||||
|     <div | 		<div | ||||||
|       class="grid gap-2 grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 2xl:grid-cols-6 sm:gap-4" | 			class="grid gap-1 grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 2xl:grid-cols-6 sm:gap-4" | ||||||
|     > | 		> | ||||||
|       <StatCard | 			<StatCard | ||||||
|         title={$_("runners")} | 				title={$_("runners")} | ||||||
|         value={stats.total_runners} | 				value={stats.total_runners} | ||||||
|         href="/runners/" | 				href="/runners/" | ||||||
|       > | 			> | ||||||
|         <svg | 				<svg | ||||||
|           height="24" | 					height="24" | ||||||
|           width="24" | 					width="24" | ||||||
|           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" | ||||||
|           ><path d="M0 0h24v24H0z" fill="none" /> | 					><path d="M0 0h24v24H0z" fill="none" /> | ||||||
|           <path | 					<path | ||||||
|             d="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1l-5.2 2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" | 						d="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1l-5.2 2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" | ||||||
|           /></svg | 					/></svg | ||||||
|         > | 				> | ||||||
|       </StatCard> | 			</StatCard> | ||||||
|       <StatCard | 			<StatCard | ||||||
|         title={$_("total-scans")} | 				title={$_("total-scans")} | ||||||
|         value={stats.total_scans} | 				value={stats.total_scans} | ||||||
|         href="/scans/" | 				href="/scans/" | ||||||
|       > | 			> | ||||||
|         <svg | 				<svg | ||||||
|           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" | 					viewBox="0 0 24 24" | ||||||
|           ><path fill="none" d="M0 0h24v24H0z" /> | 					><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|           <path | 					<path | ||||||
|             fill="currentColor" | 						fill="currentColor" | ||||||
|             d="M2 4h2v16H2V4zm4 0h1v16H6V4zm2 0h2v16H8V4zm3 0h2v16h-2V4zm3 0h2v16h-2V4zm3 0h1v16h-1V4zm2 0h3v16h-3V4z" | 						d="M2 4h2v16H2V4zm4 0h1v16H6V4zm2 0h2v16H8V4zm3 0h2v16h-2V4zm3 0h2v16h-2V4zm3 0h1v16h-1V4zm2 0h3v16h-3V4z" | ||||||
|           /></svg | 					/></svg | ||||||
|         > | 				> | ||||||
|       </StatCard> | 			</StatCard> | ||||||
|       <StatCard | 			<StatCard | ||||||
|         title={$_("total-donors")} | 				title={$_("total-donors")} | ||||||
|         value={stats.total_donors} | 				value={stats.total_donors} | ||||||
|         href="/donors/" | 				href="/donors/" | ||||||
|       > | 			> | ||||||
|         <svg | 				<svg | ||||||
|           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" | 					height="24" | ||||||
|           ><path fill="none" d="M0 0h24v24H0z" /> | 					><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" | 						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 | 					/></svg | ||||||
|         > | 				> | ||||||
|       </StatCard> | 			</StatCard> | ||||||
|       <StatCard | 			<StatCard | ||||||
|         title={$_("total-donation-count")} | 				title={$_("total-donation-count")} | ||||||
|         value={stats.total_donations} | 				value={stats.total_donations} | ||||||
|         href="/donations/" | 				href="/donations/" | ||||||
|       > | 			> | ||||||
|         <svg | 				<svg | ||||||
|           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" | 					height="24" | ||||||
|           ><path fill="none" d="M0 0h24v24H0z" /> | 					><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" | 						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 | 					/></svg | ||||||
|         > | 				> | ||||||
|       </StatCard> | 			</StatCard> | ||||||
|       <StatCard | 			<StatCard | ||||||
|         title={$_("average-donation")} | 				title={$_("average-donation")} | ||||||
|         value={`${parseFloat(stats.average_donation / 100).toLocaleString( | 				value={`${parseFloat(stats.average_donation / 100).toLocaleString( | ||||||
|           undefined, | 					undefined, | ||||||
|           { | 					{ | ||||||
|             minimumFractionDigits: 2, | 						minimumFractionDigits: 2, | ||||||
|             maximumFractionDigits: 2, | 						maximumFractionDigits: 2, | ||||||
|           } | 					} | ||||||
|         )}`} | 				)}`} | ||||||
|         href="/donations/" | 				href="/donations/" | ||||||
|       > | 			> | ||||||
|         <svg | 				<svg | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|           height="24" | 					height="24" | ||||||
|           fill="currentColor" | 					fill="currentColor" | ||||||
|           width="24" | 					width="24" | ||||||
|           ><path d="M0 0h24v24H0z" fill="none" /> | 					><path d="M0 0h24v24H0z" fill="none" /> | ||||||
|           <path | 					<path | ||||||
|             d="M15 18.5A6.48 6.48 0 019.24 15H15v-2H8.58c-.05-.33-.08-.66-.08-1s.03-.67.08-1H15V9H9.24A6.491 6.491 0 0115 5.5c1.61 0 3.09.59 4.23 1.57L21 5.3A8.955 8.955 0 0015 3c-3.92 0-7.24 2.51-8.48 6H3v2h3.06a8.262 8.262 0 000 2H3v2h3.52c1.24 3.49 4.56 6 8.48 6 2.31 0 4.41-.87 6-2.3l-1.78-1.77c-1.13.98-2.6 1.57-4.22 1.57z" | 						d="M15 18.5A6.48 6.48 0 019.24 15H15v-2H8.58c-.05-.33-.08-.66-.08-1s.03-.67.08-1H15V9H9.24A6.491 6.491 0 0115 5.5c1.61 0 3.09.59 4.23 1.57L21 5.3A8.955 8.955 0 0015 3c-3.92 0-7.24 2.51-8.48 6H3v2h3.06a8.262 8.262 0 000 2H3v2h3.52c1.24 3.49 4.56 6 8.48 6 2.31 0 4.41-.87 6-2.3l-1.78-1.77c-1.13.98-2.6 1.57-4.22 1.57z" | ||||||
|           /></svg | 					/></svg | ||||||
|         > | 				> | ||||||
|       </StatCard> | 			</StatCard> | ||||||
|       <StatCard | 			<StatCard | ||||||
|         title={$_("total-donations")} | 				title={$_("total-donations")} | ||||||
|         value={`${parseFloat(stats.total_donation / 100).toLocaleString( | 				value={`${parseFloat(stats.total_donation / 100).toLocaleString( | ||||||
|           undefined, | 					undefined, | ||||||
|           { | 					{ | ||||||
|             minimumFractionDigits: 2, | 						minimumFractionDigits: 2, | ||||||
|             maximumFractionDigits: 2, | 						maximumFractionDigits: 2, | ||||||
|           } | 					} | ||||||
|         )}`} | 				)}`} | ||||||
|         href="/donations/" | 				href="/donations/" | ||||||
|       > | 			> | ||||||
|         <svg | 				<svg | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|           height="24" | 					height="24" | ||||||
|           fill="currentColor" | 					fill="currentColor" | ||||||
|           width="24" | 					width="24" | ||||||
|           ><path d="M0 0h24v24H0z" fill="none" /> | 					><path d="M0 0h24v24H0z" fill="none" /> | ||||||
|           <path | 					<path | ||||||
|             d="M15 18.5A6.48 6.48 0 019.24 15H15v-2H8.58c-.05-.33-.08-.66-.08-1s.03-.67.08-1H15V9H9.24A6.491 6.491 0 0115 5.5c1.61 0 3.09.59 4.23 1.57L21 5.3A8.955 8.955 0 0015 3c-3.92 0-7.24 2.51-8.48 6H3v2h3.06a8.262 8.262 0 000 2H3v2h3.52c1.24 3.49 4.56 6 8.48 6 2.31 0 4.41-.87 6-2.3l-1.78-1.77c-1.13.98-2.6 1.57-4.22 1.57z" | 						d="M15 18.5A6.48 6.48 0 019.24 15H15v-2H8.58c-.05-.33-.08-.66-.08-1s.03-.67.08-1H15V9H9.24A6.491 6.491 0 0115 5.5c1.61 0 3.09.59 4.23 1.57L21 5.3A8.955 8.955 0 0015 3c-3.92 0-7.24 2.51-8.48 6H3v2h3.06a8.262 8.262 0 000 2H3v2h3.52c1.24 3.49 4.56 6 8.48 6 2.31 0 4.41-.87 6-2.3l-1.78-1.77c-1.13.98-2.6 1.57-4.22 1.57z" | ||||||
|           /></svg | 					/></svg | ||||||
|         > | 				> | ||||||
|       </StatCard> | 			</StatCard> | ||||||
|       <StatCard | 			<StatCard | ||||||
|         title={$_("total-distance")} | 				title={$_("total-distance")} | ||||||
|         value={`${stats.total_distance / 1000}km`} | 				value={`${stats.total_distance / 1000}km`} | ||||||
|         href="/scans/" | 				href="/scans/" | ||||||
|       > | 			> | ||||||
|         <svg | 				<svg | ||||||
|           fill="currentColor" | 					fill="currentColor" | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|           height="24" | 					height="24" | ||||||
|           width="24" | 					width="24" | ||||||
|           ><path d="M0 0h24v24H0z" fill="none" /> | 					><path d="M0 0h24v24H0z" fill="none" /> | ||||||
|           <path | 					<path | ||||||
|             d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H3V8h2v4h2V8h2v4h2V8h2v4h2V8h2v4h2V8h2v8z" | 						d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H3V8h2v4h2V8h2v4h2V8h2v4h2V8h2v4h2V8h2v8z" | ||||||
|           /></svg | 					/></svg | ||||||
|         > | 				> | ||||||
|       </StatCard> | 			</StatCard> | ||||||
|       <StatCard | 			<StatCard | ||||||
|         title={$_("average-distance")} | 				title={$_("average-distance")} | ||||||
|         value={`${parseFloat(stats.average_distance / 1000).toLocaleString( | 				value={`${parseFloat(stats.average_distance / 1000).toLocaleString( | ||||||
|           undefined, | 					undefined, | ||||||
|           { | 					{ | ||||||
|             minimumFractionDigits: 2, | 						minimumFractionDigits: 2, | ||||||
|             maximumFractionDigits: 2, | 						maximumFractionDigits: 2, | ||||||
|           } | 					} | ||||||
|         )}km`} | 				)}km`} | ||||||
|         href="/scans/" | 				href="/scans/" | ||||||
|       > | 			> | ||||||
|         <svg | 				<svg | ||||||
|           fill="currentColor" | 					fill="currentColor" | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|           height="24" | 					height="24" | ||||||
|           width="24" | 					width="24" | ||||||
|           ><path d="M0 0h24v24H0z" fill="none" /> | 					><path d="M0 0h24v24H0z" fill="none" /> | ||||||
|           <path | 					<path | ||||||
|             d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H3V8h2v4h2V8h2v4h2V8h2v4h2V8h2v4h2V8h2v8z" | 						d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H3V8h2v4h2V8h2v4h2V8h2v4h2V8h2v4h2V8h2v8z" | ||||||
|           /></svg | 					/></svg | ||||||
|         > | 				> | ||||||
|       </StatCard> | 			</StatCard> | ||||||
|       <StatCard | 			<StatCard | ||||||
|         title={$_("count_teams")} | 				title={$_("count_teams")} | ||||||
|         value={stats.total_teams} | 				value={stats.total_teams} | ||||||
|         href="/teams/" | 				href="/teams/" | ||||||
|       > | 			> | ||||||
|         <svg | 				<svg | ||||||
|           stroke="currentColor" | 					stroke="currentColor" | ||||||
|           fill="none" | 					fill="none" | ||||||
|           stroke-width="2" | 					stroke-width="2" | ||||||
|           viewBox="0 0 24 24" | 					viewBox="0 0 24 24" | ||||||
|           stroke-linecap="round" | 					stroke-linecap="round" | ||||||
|           stroke-linejoin="round" | 					stroke-linejoin="round" | ||||||
|           size="24" | 					size="24" | ||||||
|           class="stroke-current text-grey-500" | 					class="stroke-current text-grey-500" | ||||||
|           height="24" | 					height="24" | ||||||
|           width="24" | 					width="24" | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|           ><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" /> | 					><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" /> | ||||||
|           <circle cx="9" cy="7" r="4" /> | 					<circle cx="9" cy="7" r="4" /> | ||||||
|           <path d="M23 21v-2a4 4 0 0 0-3-3.87" /> | 					<path d="M23 21v-2a4 4 0 0 0-3-3.87" /> | ||||||
|           <path d="M16 3.13a4 4 0 0 1 0 7.75" /></svg | 					<path d="M16 3.13a4 4 0 0 1 0 7.75" /></svg | ||||||
|         > | 				> | ||||||
|       </StatCard> | 			</StatCard> | ||||||
|       <StatCard | 			<StatCard | ||||||
|         title={$_("count_organizations")} | 				title={$_("count_organizations")} | ||||||
|         value={stats.total_orgs} | 				value={stats.total_orgs} | ||||||
|         href="/orgs/" | 				href="/orgs/" | ||||||
|       > | 			> | ||||||
|         <svg | 				<svg | ||||||
|           height="24" | 					height="24" | ||||||
|           fill="currentColor" | 					fill="currentColor" | ||||||
|           width="24" | 					width="24" | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|           viewBox="0 0 24 24" | 					viewBox="0 0 24 24" | ||||||
|           ><path fill="none" d="M0 0h24v24H0z" /> | 					><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|           <path | 					<path | ||||||
|             d="M17 11V3H7v4H3v14h8v-4h2v4h8V11h-4zM7 19H5v-2h2v2zm0-4H5v-2h2v2zm0-4H5V9h2v2zm4 4H9v-2h2v2zm0-4H9V9h2v2zm0-4H9V5h2v2zm4 8h-2v-2h2v2zm0-4h-2V9h2v2zm0-4h-2V5h2v2zm4 12h-2v-2h2v2zm0-4h-2v-2h2v2z" | 						d="M17 11V3H7v4H3v14h8v-4h2v4h8V11h-4zM7 19H5v-2h2v2zm0-4H5v-2h2v2zm0-4H5V9h2v2zm4 4H9v-2h2v2zm0-4H9V9h2v2zm0-4H9V5h2v2zm4 8h-2v-2h2v2zm0-4h-2V9h2v2zm0-4h-2V5h2v2zm4 12h-2v-2h2v2zm0-4h-2v-2h2v2z" | ||||||
|           /></svg | 					/></svg | ||||||
|         > | 				> | ||||||
|       </StatCard> | 			</StatCard> | ||||||
|     </div> | 			<StatCard | ||||||
|   {:catch error} | 				title={$_("runner_via_selfservice")} | ||||||
|     <div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500"> | 				value={stats.runnersViaSelfservice} | ||||||
|       <span class="inline-block align-middle mr-8"> | 				href="/runners/" | ||||||
|         <b class="capitalize">{$_("general_promise_error")}</b> | 			> | ||||||
|         {error} | 				<svg | ||||||
|       </span> | 					height="24" | ||||||
|     </div> | 					width="24" | ||||||
|   {/await} | 					fill="currentColor" | ||||||
|  | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|  | 					viewBox="0 0 24 24" | ||||||
|  | 					><path d="M0 0h24v24H0z" fill="none" /> | ||||||
|  | 					<path | ||||||
|  | 						d="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1l-5.2 2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" | ||||||
|  | 					/></svg | ||||||
|  | 				> | ||||||
|  | 			</StatCard> | ||||||
|  | 			<StatCard | ||||||
|  | 				title={$_('runners_via_kiosk')} | ||||||
|  | 				value={stats.runnersViaKiosk} | ||||||
|  | 				href="/runners/" | ||||||
|  | 			> | ||||||
|  | 				<svg | ||||||
|  | 					height="24" | ||||||
|  | 					width="24" | ||||||
|  | 					fill="currentColor" | ||||||
|  | 					xmlns="http://www.w3.org/2000/svg" | ||||||
|  | 					viewBox="0 0 24 24" | ||||||
|  | 					><path d="M0 0h24v24H0z" fill="none" /> | ||||||
|  | 					<path | ||||||
|  | 						d="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1l-5.2 2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" | ||||||
|  | 					/></svg | ||||||
|  | 				> | ||||||
|  | 			</StatCard> | ||||||
|  | 		</div> | ||||||
|  | 	{: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} | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -7,13 +7,13 @@ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <a {href}> | <a {href}> | ||||||
|   <div class="p-4 rounded-lg bg-white border border-grey-100"> |   <div class="p-3 py-4 sm:p-4 rounded-lg bg-white border border-grey-100"> | ||||||
|     <div class="flex flex-row items-center justify-between"> |     <div class="flex flex-row items-center justify-between"> | ||||||
|       <div class="flex flex-col"> |       <div class="flex flex-col"> | ||||||
|         <div class="text-xs uppercase font-normal text-grey-500"> |         <div class="text-md sm:text-xs uppercase font-normal text-grey-500"> | ||||||
|           {title} |           {title} | ||||||
|         </div> |         </div> | ||||||
|         <div class="text-xl font-bold font-mono">{value}</div> |         <div class="text-2xl sm:text-xl font-bold font-mono">{value}</div> | ||||||
|       </div> |       </div> | ||||||
|       <slot /> |       <slot /> | ||||||
|     </div> |     </div> | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ | |||||||
|     RunnerService, |     RunnerService, | ||||||
|   } from "@odit/lfk-client-js"; |   } from "@odit/lfk-client-js"; | ||||||
|   import Select from "svelte-select"; |   import Select from "svelte-select"; | ||||||
|   import { createEventDispatcher } from "svelte"; |   import { createEventDispatcher, onMount } from "svelte"; | ||||||
|   import toast from "svelte-french-toast"; |   import toast from "svelte-french-toast"; | ||||||
|   export let modal_open; |   export let modal_open; | ||||||
|   const dispatch = createEventDispatcher(); |   const dispatch = createEventDispatcher(); | ||||||
| @@ -23,16 +23,6 @@ | |||||||
|   $: runners = []; |   $: runners = []; | ||||||
|   $: is_fixed = false; |   $: is_fixed = false; | ||||||
|   $: is_paid = false; |   $: is_paid = false; | ||||||
|   DonorService.donorControllerGetAll().then((val) => { |  | ||||||
|     donors = val.map((r) => { |  | ||||||
|       return { label: getDonorLabel(r), value: r }; |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
|   RunnerService.runnerControllerGetAll().then((val) => { |  | ||||||
|     runners = val.map((r) => { |  | ||||||
|       return { label: getDonorLabel(r), value: r }; |  | ||||||
|     }); |  | ||||||
|   }); |  | ||||||
|   $: amount_input = 0; |   $: amount_input = 0; | ||||||
|   $: processed_last_submit = true; |   $: processed_last_submit = true; | ||||||
|   $: is_amount_valid = amount_input > 0; |   $: is_amount_valid = amount_input > 0; | ||||||
| @@ -95,6 +85,7 @@ | |||||||
|             amount_input = 0; |             amount_input = 0; | ||||||
|             modal_open = false; |             modal_open = false; | ||||||
|             // |             // | ||||||
|  |             toast.dismiss(); | ||||||
|             toast.success($_("donation_added")); |             toast.success($_("donation_added")); | ||||||
|             dispatch("created", { donations: [result] }); |             dispatch("created", { donations: [result] }); | ||||||
|           }) |           }) | ||||||
| @@ -107,18 +98,31 @@ | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   onMount(async () => { | ||||||
|  |     donors = (await DonorService.donorControllerGetAll()).map( | ||||||
|  |       (r) => { | ||||||
|  |         return { label: getDonorLabel(r), value: r }; | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |     runners = (await RunnerService.runnerControllerGetAll()).map( | ||||||
|  |       (r) => { | ||||||
|  |         return { label: getDonorLabel(r), value: r }; | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -131,15 +135,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -154,14 +158,14 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {#if is_fixed} |                 {#if is_fixed} | ||||||
|                   {$_("create-a-new-fixed-donation")} |                   {$_("create-a-new-fixed-donation")} | ||||||
|                 {:else}{$_("create-a-new-distance-donation")}{/if} |                 {:else}{$_("create-a-new-distance-donation")}{/if} | ||||||
|               </h3> |               </h3> | ||||||
|               <label class="content-center align-middle object-center"> |               <label class="content-center align-middle object-center"> | ||||||
|                 <span class="ml-2 text-base" class:text-gray-300={is_fixed} |                 <span class="text-base" class:text-gray-300={is_fixed} | ||||||
|                   >{$_("distance-donation")}</span |                   >{$_("distance-donation")}</span | ||||||
|                 > |                 > | ||||||
|                 <input |                 <input | ||||||
| @@ -173,14 +177,14 @@ | |||||||
|                   >{$_("fixed-donation")}</span |                   >{$_("fixed-donation")}</span | ||||||
|                 > |                 > | ||||||
|               </label> |               </label> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "please-provide-the-nessecary-information-to-create-a-new-donation" |                     "please-provide-the-nessecary-information-to-create-a-new-donation" | ||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="donor" |                     for="donor" | ||||||
| @@ -188,7 +192,7 @@ | |||||||
|                     >{$_("donor")}</label |                     >{$_("donor")}</label | ||||||
|                   > |                   > | ||||||
|                   <Select |                   <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" |                     containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     itemFilter={(label, filterText, option) => |                     itemFilter={(label, filterText, option) => | ||||||
|                       filterDonors(label, filterText, option)} |                       filterDonors(label, filterText, option)} | ||||||
|                     items={donors} |                     items={donors} | ||||||
| @@ -208,7 +212,7 @@ | |||||||
|                       >{$_("runner")}</label |                       >{$_("runner")}</label | ||||||
|                     > |                     > | ||||||
|                     <Select |                     <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" |                       containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                       itemFilter={(label, filterText, option) => |                       itemFilter={(label, filterText, option) => | ||||||
|                         filterDonors(label, filterText, option)} |                         filterDonors(label, filterText, option)} | ||||||
|                       items={runners} |                       items={runners} | ||||||
| @@ -240,7 +244,7 @@ | |||||||
|                       type="number" |                       type="number" | ||||||
|                       step="0.01" |                       step="0.01" | ||||||
|                       name="donation_amount_eur" |                       name="donation_amount_eur" | ||||||
|                       class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 p-2" |                       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-neutral-800 p-2" | ||||||
|                       placeholder="2.00" |                       placeholder="2.00" | ||||||
|                     /> |                     /> | ||||||
|                     <span |                     <span | ||||||
| @@ -285,13 +289,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("create")} |             {$_("create")} | ||||||
|           </button> |           </button> | ||||||
| @@ -300,7 +304,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -33,7 +33,7 @@ | |||||||
|       toast.loading($_("updating-donation")); |       toast.loading($_("updating-donation")); | ||||||
|       const editable = Object.assign({}, original_data); |       const editable = Object.assign({}, original_data); | ||||||
|       editable.donor = editable.donor.id; |       editable.donor = editable.donor.id; | ||||||
|       editable.paidAmount = paid_amount_input * 100; |       editable.paidAmount = Math.round(paid_amount_input * 100); | ||||||
|       if (editable.responseType == "DISTANCEDONATION" || editable.runner) { |       if (editable.responseType == "DISTANCEDONATION" || editable.runner) { | ||||||
|         editable.runner = editable.runner.id; |         editable.runner = editable.runner.id; | ||||||
|         DonationService.donationControllerPutDistance( |         DonationService.donationControllerPutDistance( | ||||||
| @@ -46,7 +46,7 @@ | |||||||
|             toast.dismiss(); |             toast.dismiss(); | ||||||
|  |  | ||||||
|             toast.success($_("donation-updated")); |             toast.success($_("donation-updated")); | ||||||
|             dispatch("created", { donation: response }); |             dispatch("created", { donation: result }); | ||||||
|           }) |           }) | ||||||
|           .catch((err) => { |           .catch((err) => { | ||||||
|             // |             // | ||||||
| @@ -61,7 +61,7 @@ | |||||||
|             // |             // | ||||||
|             toast.dismiss(); |             toast.dismiss(); | ||||||
|             toast.success($_("donation-updated")); |             toast.success($_("donation-updated")); | ||||||
|             dispatch("created", { donation: response }); |             dispatch("created", { donation: result }); | ||||||
|           }) |           }) | ||||||
|           .catch((err) => { |           .catch((err) => { | ||||||
|             // |             // | ||||||
| @@ -76,14 +76,14 @@ | |||||||
|  |  | ||||||
| {#if payment_modal_open} | {#if payment_modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       payment_modal_open = false; |       payment_modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -96,15 +96,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -120,18 +120,18 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 text-left"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("enter-payment")} |                 {$_("enter-payment")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "you-can-enter-the-donations-paid-amount-manually-or-use-the-max-button-to-use-the-donations-exact-amount" |                     "you-can-enter-the-donations-paid-amount-manually-or-use-the-max-button-to-use-the-donations-exact-amount" | ||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols gap-6"> |               <div class="grid grid-cols gap-2 lg:gap-6"> | ||||||
|                 <div class="w-full"> |                 <div class="w-full"> | ||||||
|                   <label |                   <label | ||||||
|                     for="token" |                     for="token" | ||||||
| @@ -179,13 +179,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("save-changes")} |             {$_("save-changes")} | ||||||
|           </button> |           </button> | ||||||
| @@ -194,7 +194,7 @@ | |||||||
|               payment_modal_open = false; |               payment_modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -37,14 +37,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -57,15 +57,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -80,15 +80,10 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("confirm-delete")} |                 {$_("please-confirm-the-deletion-of-donation")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |  | ||||||
|                 <p class="text-sm text-gray-500"> |  | ||||||
|                   {$_("please-confirm-the-deletion-of-donation")} |  | ||||||
|                 </p> |  | ||||||
|               </div> |  | ||||||
|               <div class="w-full"> |               <div class="w-full"> | ||||||
|                 <span class="inline-block" |                 <span class="inline-block" | ||||||
|                   ><b>{$_("donor")}</b>: {delete_donation.donor.firstname} |                   ><b>{$_("donor")}</b>: {delete_donation.donor.firstname} | ||||||
| @@ -98,11 +93,11 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-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" | ||||||
|           > |           > | ||||||
|             {$_("delete")} |             {$_("delete")} | ||||||
|           </button> |           </button> | ||||||
| @@ -111,7 +106,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -1,364 +1,352 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import store from "../../store"; | 	import store from "../../store"; | ||||||
|   import { | 	import { | ||||||
|     DonationService, | 		DonationService, | ||||||
|     DonorService, | 		DonorService, | ||||||
|     RunnerService, | 		RunnerService, | ||||||
|   } from "@odit/lfk-client-js"; | 	} from "@odit/lfk-client-js"; | ||||||
|  | 	import toast from "svelte-french-toast"; | ||||||
|  |  | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; | 	import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   import Select from "svelte-select"; | 	import Select from "svelte-select"; | ||||||
|   let data_loaded = false; | 	let data_loaded = false; | ||||||
|   export let params; | 	export let params; | ||||||
|   $: delete_triggered = false; | 	$: delete_triggered = false; | ||||||
|   $: original_data = {}; | 	$: original_data = {}; | ||||||
|   $: editable = {}; | 	$: editable = {}; | ||||||
|   $: donor = {}; | 	$: donor = {}; | ||||||
|   $: runner = {}; | 	$: runner = {}; | ||||||
|   $: current_donors = []; | 	$: current_donors = []; | ||||||
|   $: current_runners = []; | 	$: current_runners = []; | ||||||
|   $: amount_input = 0; | 	$: amount_input = 0; | ||||||
|   $: is_amount_valid = amount_input > 0; | 	$: is_amount_valid = amount_input > 0; | ||||||
|   $: paid_amount_input = 0; | 	$: paid_amount_input = 0; | ||||||
|   $: is_paid_amount_valid = paid_amount_input > 0; | 	$: is_paid_amount_valid = paid_amount_input > 0; | ||||||
|   $: is_everything_set = | 	$: is_everything_set = | ||||||
|     editable.donor != null && | 		editable.donor != null && | ||||||
|     ((original_data.responseType == "DISTANCEDONATION" && | 		((original_data.responseType == "DISTANCEDONATION" && | ||||||
|       editable?.runner != null) || | 			editable?.runner != null) || | ||||||
|       original_data.responseType !== "DISTANCEDONATION"); | 			original_data.responseType !== "DISTANCEDONATION"); | ||||||
|   $: changes_performed = | 	$: changes_performed = | ||||||
|     !(JSON.stringify(original_data) === JSON.stringify(editable)) || | 		!(JSON.stringify(original_data) === JSON.stringify(editable)) || | ||||||
|     (original_data.responseType == "DISTANCEDONATION" && | 		(original_data.responseType == "DISTANCEDONATION" && | ||||||
|       !(Math.floor(amount_input * 100) === original_data.amountPerDistance)) || | 			!(Math.floor(amount_input * 100) === original_data.amountPerDistance)) || | ||||||
|     (original_data.responseType !== "DISTANCEDONATION" && | 		(original_data.responseType !== "DISTANCEDONATION" && | ||||||
|       !(Math.floor(amount_input * 100) === original_data.amount)) || | 			!(Math.floor(amount_input * 100) === original_data.amount)) || | ||||||
|     !(Math.floor(paid_amount_input * 100) === original_data.paidAmount); | 		!(Math.floor(paid_amount_input * 100) === original_data.paidAmount); | ||||||
|   $: save_enabled = changes_performed && is_amount_valid && is_everything_set; | 	$: save_enabled = changes_performed && is_amount_valid && is_everything_set; | ||||||
|  |  | ||||||
|   const promise = DonationService.donationControllerGetOne( | 	const promise = DonationService.donationControllerGetOne( | ||||||
|     params.donationid | 		params.donationid | ||||||
|   ).then((data) => { | 	).then((data) => { | ||||||
|     data_loaded = true; | 		data_loaded = true; | ||||||
|     original_data = Object.assign({}, data); | 		original_data = Object.assign({}, data); | ||||||
|     editable = Object.assign({}, original_data); | 		editable = Object.assign({}, original_data); | ||||||
|     paid_amount_input = data.paidAmount / 100; | 		paid_amount_input = data.paidAmount / 100; | ||||||
|     if (data.responseType == "DISTANCEDONATION") { | 		if (data.responseType == "DISTANCEDONATION") { | ||||||
|       amount_input = data.amountPerDistance / 100; | 			amount_input = data.amountPerDistance / 100; | ||||||
|       RunnerService.runnerControllerGetAll().then((val) => { | 			RunnerService.runnerControllerGetAll().then((val) => { | ||||||
|         current_runners = val.map((r) => { | 				current_runners = val.map((r) => { | ||||||
|           return { label: getDonorLabel(r), value: r }; | 					return { label: getDonorLabel(r), value: r }; | ||||||
|         }); | 				}); | ||||||
|         runner = current_runners.find((g) => g.value.id == editable.runner.id); | 				runner = current_runners.find((g) => g.value.id == editable.runner.id); | ||||||
|       }); | 			}); | ||||||
|     } else { | 		} else { | ||||||
|       amount_input = data.amount / 100; | 			amount_input = data.amount / 100; | ||||||
|     } | 		} | ||||||
|     DonorService.donorControllerGetAll().then((val) => { | 		DonorService.donorControllerGetAll().then((val) => { | ||||||
|       current_donors = val.map((r) => { | 			current_donors = val.map((r) => { | ||||||
|         return { label: getDonorLabel(r), value: r }; | 				return { label: getDonorLabel(r), value: r }; | ||||||
|       }); | 			}); | ||||||
|       donor = current_donors.find((g) => g.value.id == editable.donor.id); | 			donor = current_donors.find((g) => g.value.id == editable.donor.id); | ||||||
|     }); | 		}); | ||||||
|   }); | 	}); | ||||||
|   const getDonorLabel = (option) => | 	const getDonorLabel = (option) => | ||||||
|     option.firstname + " " + (option.middlename || "") + " " + option.lastname; | 		option.firstname + " " + (option.middlename || "") + " " + option.lastname; | ||||||
|   const filterDonors = (label, filterText, option) => | 	const filterDonors = (label, filterText, option) => | ||||||
|     label.toLowerCase().includes(filterText.toLowerCase()) || | 		label.toLowerCase().includes(filterText.toLowerCase()) || | ||||||
|     option.value.id.toString().startsWith(filterText.toLowerCase()); | 		option.value.id.toString().startsWith(filterText.toLowerCase()); | ||||||
|  |  | ||||||
|   function submit() { | 	function submit() { | ||||||
|     if (data_loaded === true && save_enabled) { | 		if (data_loaded === true && save_enabled) { | ||||||
|       toast($_("updating-donation")); | 			toast($_("updating-donation")); | ||||||
|       let postdata = {}; | 			let postdata = {}; | ||||||
|       editable.paidAmount = paid_amount_input * 100; | 			editable.paidAmount = paid_amount_input * 100; | ||||||
|       if (original_data.responseType === "DISTANCEDONATION") { | 			if (original_data.responseType === "DISTANCEDONATION") { | ||||||
|         editable.amountPerDistance = Math.floor(amount_input * 100); | 				editable.amountPerDistance = Math.floor(amount_input * 100); | ||||||
|         postdata = Object.assign(postdata, editable); | 				postdata = Object.assign(postdata, editable); | ||||||
|         postdata.runner = postdata.runner.id; | 				postdata.runner = postdata.runner.id; | ||||||
|         postdata.donor = postdata.donor.id; | 				postdata.donor = postdata.donor.id; | ||||||
|         DonationService.donationControllerPutDistance( | 				DonationService.donationControllerPutDistance( | ||||||
|           original_data.id, | 					original_data.id, | ||||||
|           postdata | 					postdata | ||||||
|         ) | 				) | ||||||
|           .then((resp) => { | 					.then((resp) => { | ||||||
|             Object.assign(original_data, editable); | 						Object.assign(original_data, editable); | ||||||
|             original_data = original_data; | 						original_data = original_data; | ||||||
|             toast.success($_("donation-updated")); | 						toast.success($_("donation-updated")); | ||||||
|           }) | 					}) | ||||||
|           .catch((err) => {}); | 					.catch((err) => {}); | ||||||
|       } else { | 			} else { | ||||||
|         editable.amount = Math.floor(amount_input * 100); | 				editable.amount = Math.floor(amount_input * 100); | ||||||
|         postdata = Object.assign(postdata, editable); | 				postdata = Object.assign(postdata, editable); | ||||||
|         postdata.donor = postdata.donor.id; | 				postdata.donor = postdata.donor.id; | ||||||
|         DonationService.donationControllerPutFixed(original_data.id, postdata) | 				DonationService.donationControllerPutFixed(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; | ||||||
|             toast.success($_("donation-updated")); | 						toast.success($_("donation-updated")); | ||||||
|           }) | 					}) | ||||||
|           .catch((err) => {}); | 					.catch((err) => {}); | ||||||
|       } | 			} | ||||||
|     } else { | 		} else { | ||||||
|     } | 		} | ||||||
|   } | 	} | ||||||
|   function deleteDonation() { | 	function deleteDonation() { | ||||||
|     DonationService.donationControllerRemove(original_data.id, false) | 		DonationService.donationControllerRemove(original_data.id, false) | ||||||
|       .then((resp) => { | 			.then((resp) => { | ||||||
|         toast($_("donation-deleted")); | 				toast.success($_("donation-deleted")); | ||||||
|         location.replace("./"); | 				location.replace("./"); | ||||||
|       }) | 			}) | ||||||
|       .catch((err) => { | 			.catch((err) => { | ||||||
|         modal_open = true; | 				modal_open = true; | ||||||
|         delete_donor = original_data; | 				delete_donor = original_data; | ||||||
|       }); | 			}); | ||||||
|   } | 	} | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#await promise} | {#await promise} | ||||||
|   {$_("loading-donation-details")} | 	{$_("loading-donation-details")} | ||||||
| {:then} | {:then} | ||||||
|   <section class="container p-5 select-none"> | 	<section class="container p-5 select-none"> | ||||||
|     <div class="flex flex-row mb-4"> | 		<div class="flex flex-row mb-4"> | ||||||
|       <div class="w-full"> | 			<div class="mt-2 w-full"> | ||||||
|         <nav class="w-full flex"> | 				<nav class="w-full flex"> | ||||||
|           <ol class="list-none flex flex-row items-center justify-start"> | 					<ol class="list-none flex flex-row items-center justify-start"> | ||||||
|             <li class="flex items-center"> | 						<li class="flex items-center"> | ||||||
|               <svg | 							<a class="mr-2" href="./" | ||||||
|                 fill="currentColor" | 								><svg | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 									xmlns="http://www.w3.org/2000/svg" | ||||||
|                 viewBox="0 0 24 24" | 									width="24" | ||||||
|                 width="24" | 									height="24" | ||||||
|                 height="24" | 									viewBox="0 0 24 24" | ||||||
|                 ><path fill="none" d="M0 0h24v24H0z" /> | 									fill="none" | ||||||
|                 <path | 									stroke="currentColor" | ||||||
|                   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" | 									stroke-width="2" | ||||||
|                 /></svg | 									stroke-linecap="round" | ||||||
|               > | 									stroke-linejoin="round" | ||||||
|             </li> | 									class="inline-block" | ||||||
|             <li class="flex items-center ml-2"> | 									><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg | ||||||
|               <a class="mr-2" href="./">{$_("donations")}</a><svg | 								> | ||||||
|                 stroke="currentColor" | 								{$_("donations")}</a | ||||||
|                 fill="none" | 							> | ||||||
|                 stroke-width="2" | 						</li> | ||||||
|                 viewBox="0 0 24 24" | 					</ol> | ||||||
|                 stroke-linecap="round" | 				</nav> | ||||||
|                 stroke-linejoin="round" | 			</div> | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" | 		</div> | ||||||
|                 height="1em" | 		<div class="mb-4 text-3xl font-extrabold leading-tight"> | ||||||
|                 width="1em" | 			{original_data.donor.firstname} | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 			{original_data.donor.middlename || ""} | ||||||
|                 ><line x1="5" y1="12" x2="19" y2="12" /> | 			{original_data.donor.lastname} | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg | 			> | ||||||
|               > | 			{#if original_data.responseType == "DISTANCEDONATION"} | ||||||
|             </li> | 				{original_data.runner.firstname} | ||||||
|             <li class="flex items-center"> | 				{original_data.runner.middlename || ""} | ||||||
|               <span class="mr-2">{original_data.id}</span> | 				{original_data.runner.lastname} | ||||||
|             </li> | 			{:else} | ||||||
|           </ol> | 				{$_("fixed-donation")}: | ||||||
|         </nav> | 				{amount_input.toFixed(2).toLocaleString("de-DE", { valute: "EUR" })}€ | ||||||
|       </div> | 			{/if} | ||||||
|     </div> | 			[#{original_data.id}] | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> | 			<div data-id="donation_actions_${original_data.id}"> | ||||||
|       {original_data.donor.firstname} | 				{#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:DELETE")} | ||||||
|       {original_data.donor.middlename || ""} | 					{#if delete_triggered} | ||||||
|       {original_data.donor.lastname} | 						<button | ||||||
|       > | 							on:click={deleteDonation} | ||||||
|       {#if original_data.responseType == "DISTANCEDONATION"} | 							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:w-auto sm:text-sm" | ||||||
|         {original_data.runner.firstname} | 							>{$_("confirm-deletion")}</button | ||||||
|         {original_data.runner.middlename || ""} | 						> | ||||||
|         {original_data.runner.lastname} | 						<button | ||||||
|       {:else} | 							on:click={() => { | ||||||
|         {$_("fixed-donation")}: | 								delete_triggered = !delete_triggered; | ||||||
|         {amount_input.toFixed(2).toLocaleString("de-DE", { valute: "EUR" })}€ | 							}} | ||||||
|       {/if} | 							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" | ||||||
|       <span data-id="donation_actions_${original_data.id}"> | 							>{$_("cancel")}</button | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:DELETE")} | 						> | ||||||
|           {#if delete_triggered} | 					{/if} | ||||||
|             <button | 					{#if !delete_triggered} | ||||||
|               on:click={deleteDonation} | 						<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:" | 							on:click={() => { | ||||||
|               >{$_("confirm-deletion")}</button | 								delete_triggered = true; | ||||||
|             > | 							}} | ||||||
|             <button | 							type="button" | ||||||
|               on:click={() => { | 							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:w-auto sm:text-sm" | ||||||
|                 delete_triggered = !delete_triggered; | 							>{$_("delete-donation")}</button | ||||||
|               }} | 						> | ||||||
|               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:" | 					{/if} | ||||||
|               >{$_("cancel")}</button | 				{/if} | ||||||
|             > | 				{#if !delete_triggered} | ||||||
|           {/if} | 					<button | ||||||
|           {#if !delete_triggered} | 						disabled={!save_enabled} | ||||||
|             <button | 						class:opacity-50={!save_enabled} | ||||||
|               on:click={() => { | 						type="button" | ||||||
|                 delete_triggered = true; | 						on:click={submit} | ||||||
|               }} | 						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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|               type="button" | 						>{$_("save-changes")}</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:" | 					> | ||||||
|               >{$_("delete-donation")}</button | 				{/if} | ||||||
|             > | 			</div> | ||||||
|           {/if} | 		</div> | ||||||
|         {/if} | 		<!--  --> | ||||||
|         {#if !delete_triggered} | 		<div> | ||||||
|           <button | 			<span class="font-semibold text-gray-700" | ||||||
|             disabled={!save_enabled} | 				>{$_("total-donation-amount")}:</span | ||||||
|             class:opacity-50={!save_enabled} | 			> | ||||||
|             type="button" | 			<span | ||||||
|             on:click={submit} | 				>{(editable.amount / 100) | ||||||
|             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:" | 					.toFixed(2) | ||||||
|             >{$_("save-changes")}</button | 					.toLocaleString("de-DE", { valute: "EUR" })}€</span | ||||||
|           > | 			> | ||||||
|         {/if} | 			| | ||||||
|       </span> | 			<span class="font-semibold text-gray-700">{$_("paid-amount")}:</span> | ||||||
|     </div> | 			<span | ||||||
|     <!--  --> | 				>{(editable.paidAmount / 100) | ||||||
|     <div> | 					.toFixed(2) | ||||||
|       <span class="font-medium text-gray-700" | 					.toLocaleString("de-DE", { valute: "EUR" })}€</span | ||||||
|         >{$_("total-donation-amount")}:</span | 			> | ||||||
|       > | 			| | ||||||
|       <span | 			<span class="font-semibold text-gray-700">{$_("status")}:</span> | ||||||
|         >{(editable.amount / 100) | 			{#if editable.status == "PAID"} | ||||||
|           .toFixed(2) | 				<span | ||||||
|           .toLocaleString("de-DE", { valute: "EUR" })}€</span | 					class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-100 text-green-800" | ||||||
|       > | 					>{$_("paid")}</span | ||||||
|       | | 				> | ||||||
|       <span class="font-medium text-gray-700">{$_("paid-amount")}:</span> | 			{:else} | ||||||
|       <span | 				<span | ||||||
|         >{(editable.paidAmount / 100) | 					class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-red-100 text-red-800" | ||||||
|           .toFixed(2) | 					>{$_("open")}</span | ||||||
|           .toLocaleString("de-DE", { valute: "EUR" })}€</span | 				> | ||||||
|       > | 			{/if} | ||||||
|       | | 		</div> | ||||||
|       <span class="font-medium text-gray-700">{$_("status")}:</span> | 		<br /> | ||||||
|       {#if editable.status == "PAID"} | 		<div class=" mt-2 w-full"> | ||||||
|         <span | 			<label for="donor" class="block font-semibold text-gray-700" | ||||||
|           class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800" | 				>{$_("donor")}</label | ||||||
|           >{$_("paid")}</span | 			> | ||||||
|         > | 			<Select | ||||||
|       {:else} | 				containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|         <span | 				itemFilter={(label, filterText, option) => | ||||||
|           class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800" | 					filterDonors(label, filterText, option)} | ||||||
|           >{$_("open")}</span | 				items={current_donors} | ||||||
|         > | 				showChevron={true} | ||||||
|       {/if} | 				placeholder={$_("search-for-donor-name-or-id")} | ||||||
|     </div> | 				noOptionsMessage={$_("no-donors-found")} | ||||||
|     <br /> | 				bind:selectedValue={donor} | ||||||
|     <div class=" w-full"> | 				on:select={(selectedValue) => { | ||||||
|       <label for="donor" class="block font-medium text-gray-700" | 					editable.donor = selectedValue.detail.value; | ||||||
|         >{$_("donor")}</label | 					editable.donor.donationAmount = original_data.donor.donationAmount; | ||||||
|       > | 					editable.donor.paidDonationAmount = | ||||||
|       <Select | 						original_data.donor.paidDonationAmount; | ||||||
|         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) => | 				on:clear={() => (editable.donor = null)} | ||||||
|           filterDonors(label, filterText, option)} | 			/> | ||||||
|         items={current_donors} | 		</div> | ||||||
|         showChevron={true} | 		{#if original_data.responseType == "DISTANCEDONATION"} | ||||||
|         placeholder={$_("search-for-donor-name-or-id")} | 			<div class=" mt-2 w-full"> | ||||||
|         noOptionsMessage={$_("no-donors-found")} | 				<label for="donor" class="block font-semibold text-gray-700" | ||||||
|         bind:selectedValue={donor} | 					>{$_("runner")}</label | ||||||
|         on:select={(selectedValue) => { | 				> | ||||||
|           editable.donor = selectedValue.detail.value; | 				<Select | ||||||
|           editable.donor.donationAmount = original_data.donor.donationAmount; | 					containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|           editable.donor.paidDonationAmount = | 					itemFilter={(label, filterText, option) => | ||||||
|             original_data.donor.paidDonationAmount; | 						filterDonors(label, filterText, option)} | ||||||
|         }} | 					items={current_runners} | ||||||
|         on:clear={() => (editable.donor = null)} | 					showChevron={true} | ||||||
|       /> | 					placeholder={$_("search-for-runner-by-name-or-id")} | ||||||
|     </div> | 					noOptionsMessage={$_("no-runners-found")} | ||||||
|     {#if original_data.responseType == "DISTANCEDONATION"} | 					bind:selectedValue={runner} | ||||||
|       <div class=" w-full"> | 					on:select={(selectedValue) => | ||||||
|         <label for="donor" class="block font-medium text-gray-700" | 						(editable.runner = selectedValue.detail.value)} | ||||||
|           >{$_("runner")}</label | 					on:clear={() => (editable.runner = null)} | ||||||
|         > | 				/> | ||||||
|         <Select | 			</div> | ||||||
|           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" | 		{/if} | ||||||
|           itemFilter={(label, filterText, option) => | 		<div class=" mt-2 w-full"> | ||||||
|             filterDonors(label, filterText, option)} | 			<label for="lastname" class="font-semibold text-gray-700"> | ||||||
|           items={current_runners} | 				{#if original_data.responseType == "DISTANCEDONATION"} | ||||||
|           showChevron={true} | 					{$_("amount-per-kilometer")} | ||||||
|           placeholder={$_("search-for-runner-by-name-or-id")} | 				{:else}{$_("donation-amount")}{/if} | ||||||
|           noOptionsMessage={$_("no-runners-found")} | 			</label> | ||||||
|           bind:selectedValue={runner} | 			<div class="mt-1 flex rounded-md shadow-sm"> | ||||||
|           on:select={(selectedValue) => | 				<input | ||||||
|             (editable.runner = selectedValue.detail.value)} | 					autocomplete="off" | ||||||
|           on:clear={() => (editable.runner = null)} | 					class:border-red-500={!is_amount_valid} | ||||||
|         /> | 					class:focus:border-red-500={!is_amount_valid} | ||||||
|       </div> | 					class:focus:ring-red-500={!is_amount_valid} | ||||||
|     {/if} | 					bind:value={amount_input} | ||||||
|     <div class=" w-full"> | 					type="number" | ||||||
|       <label for="lastname" class="font-medium text-gray-700"> | 					step="0.01" | ||||||
|         {#if original_data.responseType == "DISTANCEDONATION"} | 					name="donation_amount_eur" | ||||||
|           {$_("amount-per-kilometer")} | 					class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 p-2" | ||||||
|         {:else}{$_("donation-amount")}{/if} | 					placeholder="2.00" | ||||||
|       </label> | 				/> | ||||||
|       <div class="mt-1 flex rounded-md shadow-sm"> | 				<span | ||||||
|         <input | 					class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500" | ||||||
|           autocomplete="off" | 					>€</span | ||||||
|           class:border-red-500={!is_amount_valid} | 				> | ||||||
|           class:focus:border-red-500={!is_amount_valid} | 			</div> | ||||||
|           class:focus:ring-red-500={!is_amount_valid} | 			{#if !is_amount_valid} | ||||||
|           bind:value={amount_input} | 				<span | ||||||
|           type="number" | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|           step="0.01" | 				> | ||||||
|           name="donation_amount_eur" | 					{$_("donation-amount-must-be-greater-that-0-00eur")} | ||||||
|           class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm: border-gray-300 border bg-gray-50 text-gray-500 p-2" | 				</span> | ||||||
|           placeholder="2.00" | 			{/if} | ||||||
|         /> | 		</div> | ||||||
|         <span | 		<div class="mt-2 w-full"> | ||||||
|           class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500" | 			<label for="token" class="block font-semibold text-gray-700" | ||||||
|           >€</span | 				>{$_("paid-amount")}</label | ||||||
|         > | 			> | ||||||
|       </div> | 			<div | ||||||
|       {#if !is_amount_valid} | 				class="inline-flex border-gray-300 border rounded-l-md rounded-r-md bg-gray-50 text-gray-500 w-full" | ||||||
|         <span | 			> | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 				<input | ||||||
|         > | 					autocomplete="off" | ||||||
|           {$_("donation-amount-must-be-greater-that-0-00eur")} | 					class:border-red-500={!is_amount_valid} | ||||||
|         </span> | 					class:focus:border-red-500={!is_amount_valid} | ||||||
|       {/if} | 					class:focus:ring-red-500={!is_amount_valid} | ||||||
|     </div> | 					bind:value={paid_amount_input} | ||||||
|     <div class="w-full"> | 					type="number" | ||||||
|       <label for="token" class="block text-sm font-medium text-gray-700" | 					step="0.01" | ||||||
|         >{$_("paid-amount")}</label | 					name="donation_amount_eur" | ||||||
|       > | 					class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm p-2" | ||||||
|       <div | 					placeholder="2.00" | ||||||
|         class="inline-flex border-gray-300 border rounded-l-md rounded-r-md bg-gray-50 text-gray-500 w-full" | 				/> | ||||||
|       > | 				<button | ||||||
|         <input | 					on:click={() => { | ||||||
|           autocomplete="off" | 						paid_amount_input = paid_amount_input = ( | ||||||
|           class:border-red-500={!is_amount_valid} | 							original_data.amount / 100 | ||||||
|           class:focus:border-red-500={!is_amount_valid} | 						).toFixed(2); | ||||||
|           class:focus:ring-red-500={!is_amount_valid} | 					}} | ||||||
|           bind:value={paid_amount_input} | 					class="inline-flex items-center p-r-2 text-indigo-300 hover:text-indigo-700 text-sm" | ||||||
|           type="number" | 					>MAX</button | ||||||
|           step="0.01" | 				> | ||||||
|           name="donation_amount_eur" | 				<span | ||||||
|           class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm p-2" | 					class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm" | ||||||
|           placeholder="2.00" | 					>€</span | ||||||
|         /> | 				> | ||||||
|         <button | 			</div> | ||||||
|           on:click={() => { | 			{#if !is_paid_amount_valid} | ||||||
|             paid_amount_input = paid_amount_input = ( | 				<span | ||||||
|               original_data.amount / 100 | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|             ).toFixed(2); | 				> | ||||||
|           }} | 					{$_("payment-amount-must-be-greater-than-0-00eur")} | ||||||
|           class="inline-flex items-center p-r-2 text-indigo-300 hover:text-indigo-700 text-sm" | 				</span> | ||||||
|           >MAX</button | 			{/if} | ||||||
|         > | 		</div> | ||||||
|         <span | 	</section> | ||||||
|           class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm" |  | ||||||
|           >€</span |  | ||||||
|         > |  | ||||||
|       </div> |  | ||||||
|       {#if !is_paid_amount_valid} |  | ||||||
|         <span |  | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" |  | ||||||
|         > |  | ||||||
|           {$_("payment-amount-must-be-greater-than-0-00eur")} |  | ||||||
|         </span> |  | ||||||
|       {/if} |  | ||||||
|     </div> |  | ||||||
|   </section> |  | ||||||
| {:catch error} | {:catch error} | ||||||
|   <PromiseError {error} /> | 	<PromiseError {error} /> | ||||||
| {/await} | {/await} | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
|   <div class="flex items-center"> |   <div class="flex items-center"> | ||||||
|     <a |     <a | ||||||
|       href="../donors/{donor.id}" |       href="../donors/{donor.id}" | ||||||
|       class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800" |       class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current" | ||||||
|       >{donor.firstname} |       >{donor.firstname} | ||||||
|       {#if donor.middlename}{donor.middlename}{/if} |       {#if donor.middlename}{donor.middlename}{/if} | ||||||
|       {donor.lastname}</a |       {donor.lastname}</a | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
|   <div class="text-sm font-medium text-gray-900"> |   <div class="text-sm font-medium text-gray-900"> | ||||||
|     <a |     <a | ||||||
|       href="../runners/{runner.id}" |       href="../runners/{runner.id}" | ||||||
|       class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800" |       class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current" | ||||||
|       >{runner.firstname} |       >{runner.firstname} | ||||||
|       {#if runner.middlename}{runner.middlename}{/if} |       {#if runner.middlename}{runner.middlename}{/if} | ||||||
|       {runner.lastname}</a |       {runner.lastname}</a | ||||||
|   | |||||||
| @@ -5,12 +5,12 @@ | |||||||
|  |  | ||||||
| {#if status == "PAID"} | {#if status == "PAID"} | ||||||
|   <span |   <span | ||||||
|     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800" |     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-100 text-green-800" | ||||||
|     >{$_("paid")}</span |     >{$_("paid")}</span | ||||||
|   > |   > | ||||||
| {:else} | {:else} | ||||||
|   <span |   <span | ||||||
|     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800" |     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-red-100 text-red-800" | ||||||
|     >{$_("open")}</span |     >{$_("open")}</span | ||||||
|   > |   > | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -9,20 +9,20 @@ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> |   <h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_("donations")} |     {$_("donations")} | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:CREATE")} |   </h4> | ||||||
|       <button |   {#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:CREATE")} | ||||||
|         on:click={() => { |     <button | ||||||
|           modal_open = true; |       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" |       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:w-auto sm:text-sm" | ||||||
|         {$_("add-donation")} |     > | ||||||
|       </button> |       {$_("add-donation")} | ||||||
|     {/if} |     </button> | ||||||
|   </span> |   {/if} | ||||||
|   <DonationsOverview bind:current_donations bind:addDonations /> |   <DonationsOverview bind:current_donations bind:addDonations /> | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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="m-auto" style="height:15rem" src={donations_empty} alt="" /> |     <img class="m-auto mt-2" 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> | ||||||
|   | |||||||
| @@ -163,12 +163,12 @@ | |||||||
|       ...options, |       ...options, | ||||||
|       data: current_donations, |       data: current_donations, | ||||||
|     })); |     })); | ||||||
|     toast($_("donation-deleted")); |     toast.success($_("donation-deleted")); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   onMount(async () => { |   onMount(async () => { | ||||||
|     let page = 0; |     let page = 0; | ||||||
|     let pagesize = 100; |     let pagesize = 300; | ||||||
|     while (page >= 0) { |     while (page >= 0) { | ||||||
|       const donations = await DonationService.donationControllerGetAll( |       const donations = await DonationService.donationControllerGetAll( | ||||||
|         page, |         page, | ||||||
| @@ -186,7 +186,6 @@ | |||||||
|  |  | ||||||
|       dataLoaded = true; |       dataLoaded = true; | ||||||
|       page++; |       page++; | ||||||
|       pagesize += 100; |  | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| </script> | </script> | ||||||
| @@ -196,9 +195,12 @@ | |||||||
|   payment_modal_open={active_edits.length > 0} |   payment_modal_open={active_edits.length > 0} | ||||||
|   paid_amount_input={(active_edits[0]?.paidAmount || 0) / 100} |   paid_amount_input={(active_edits[0]?.paidAmount || 0) / 100} | ||||||
|   on:created={(event) => { |   on:created={(event) => { | ||||||
|     current_donations[ |     current_donations = current_donations.map((d)=>{ | ||||||
|       current_donations.findIndex((d) => d.id === event.detail.donation.id) |       if(d.id === event.detail.donation.id){ | ||||||
|     ].paidAmount = event.detail.donation.paidAmount; |         d.paidAmount = event.detail.donation.paidAmount; | ||||||
|  |       } | ||||||
|  |       return d; | ||||||
|  |     }) | ||||||
|     options.update((options) => ({ |     options.update((options) => ({ | ||||||
|       ...options, |       ...options, | ||||||
|       data: current_donations, |       data: current_donations, | ||||||
| @@ -229,7 +231,7 @@ | |||||||
|       bind:value={searchvalue} |       bind:value={searchvalue} | ||||||
|       placeholder={$_("datatable.search")} |       placeholder={$_("datatable.search")} | ||||||
|       aria-label={$_("datatable.search")} |       aria-label={$_("datatable.search")} | ||||||
|       class="mb-4" |       class="mb-2 w-full sm:w-auto mt-1 sm:mt-0 p-2 rounded-md border" | ||||||
|     /> |     /> | ||||||
|     <div |     <div | ||||||
|       class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll" |       class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll" | ||||||
|   | |||||||
| @@ -124,14 +124,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -144,15 +144,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -167,18 +167,18 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("create-a-new-donor")} |                 {$_("create-a-new-donor")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "please-provide-the-nessecary-information-to-add-a-new-donor" |                     "please-provide-the-nessecary-information-to-add-a-new-donor" | ||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="firstname" |                     for="firstname" | ||||||
| @@ -196,7 +196,7 @@ | |||||||
|                     bind:this={firstname_input} |                     bind:this={firstname_input} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="firstname" |                     name="firstname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isFirstnameValid} |                   {#if !isFirstnameValid} | ||||||
|                     <span |                     <span | ||||||
| @@ -219,7 +219,7 @@ | |||||||
|                     bind:this={middlename_input} |                     bind:this={middlename_input} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="trackname" |                     name="trackname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
| @@ -238,7 +238,7 @@ | |||||||
|                     bind:this={lastname_input} |                     bind:this={lastname_input} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="lastname" |                     name="lastname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isLastnameValid} |                   {#if !isLastnameValid} | ||||||
|                     <span |                     <span | ||||||
| @@ -264,7 +264,7 @@ | |||||||
|                     bind:this={phone_input} |                     bind:this={phone_input} | ||||||
|                     type="tel" |                     type="tel" | ||||||
|                     name="phone" |                     name="phone" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isPhoneValidOrEmpty} |                   {#if !isPhoneValidOrEmpty} | ||||||
|                     <span |                     <span | ||||||
| @@ -292,7 +292,7 @@ | |||||||
|                     bind:this={email_input} |                     bind:this={email_input} | ||||||
|                     type="email" |                     type="email" | ||||||
|                     name="email" |                     name="email" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isEmailValidOrEmpty} |                   {#if !isEmailValidOrEmpty} | ||||||
|                     <span |                     <span | ||||||
| @@ -313,7 +313,7 @@ | |||||||
|                     /> |                     /> | ||||||
|                   </div> |                   </div> | ||||||
|                   <div class="ml-3 text-sm"> |                   <div class="ml-3 text-sm"> | ||||||
|                     <label for="comments" class="font-medium text-gray-700" |                     <label for="comments" class="font-semibold text-gray-700" | ||||||
|                       >{$_("receipt-needed")}</label |                       >{$_("receipt-needed")}</label | ||||||
|                     > |                     > | ||||||
|                   </div> |                   </div> | ||||||
| @@ -335,7 +335,7 @@ | |||||||
|                       bind:this={address_input1} |                       bind:this={address_input1} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="address1" |                       name="address1" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                     {#if !isAddress1Valid} |                     {#if !isAddress1Valid} | ||||||
|                       <span |                       <span | ||||||
| @@ -358,7 +358,7 @@ | |||||||
|                       bind:this={address_input2} |                       bind:this={address_input2} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="address2" |                       name="address2" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                   </div> |                   </div> | ||||||
|                   <div class="col-span-6"> |                   <div class="col-span-6"> | ||||||
| @@ -377,7 +377,7 @@ | |||||||
|                       bind:this={address_zipcode} |                       bind:this={address_zipcode} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="zipcode" |                       name="zipcode" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                     {#if !iszipcodevalid} |                     {#if !iszipcodevalid} | ||||||
|                       <span |                       <span | ||||||
| @@ -403,7 +403,7 @@ | |||||||
|                       bind:this={address_city} |                       bind:this={address_city} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="city" |                       name="city" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                     {#if !iscityvalid} |                     {#if !iscityvalid} | ||||||
|                       <span |                       <span | ||||||
| @@ -418,13 +418,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("create")} |             {$_("create")} | ||||||
|           </button> |           </button> | ||||||
| @@ -433,7 +433,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -1,95 +1,90 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import { clickOutside } from "../base/outsideclick"; | 	import { clickOutside } from "../base/outsideclick"; | ||||||
|  | 	import { createEventDispatcher } from "svelte"; | ||||||
|   import { DonorService } from "@odit/lfk-client-js"; | 	export let modal_open; | ||||||
|  | 	export let delete_donor; | ||||||
|   import { createEventDispatcher } from "svelte"; | 	const dispatch = createEventDispatcher(); | ||||||
|   export let modal_open; | 	function cancelDelete() { | ||||||
|   export let delete_donor; | 		modal_open = false; | ||||||
|   const dispatch = createEventDispatcher(); | 		dispatch("cancelDelete", { id: delete_donor.id }); | ||||||
|   function cancelDelete() { | 	} | ||||||
|     modal_open = false; | 	function deleteDonor() { | ||||||
|     dispatch("cancelDelete", { id: delete_donor.id }); | 		dispatch("delete", { id: delete_donor.id }); | ||||||
|   } | 	} | ||||||
|   function deleteDonor() { |  | ||||||
|     dispatch("delete", { id: delete_donor.id }); |  | ||||||
|   } |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div | 	<div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" | 		class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside | 		use:clickOutside | ||||||
|     on:click_outside={cancelDelete} | 		on:click_outside={cancelDelete} | ||||||
|   > | 	> | ||||||
|     <div | 		<div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" | 			class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > | 		> | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | 			<div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div | 				<div | ||||||
|           class="absolute inset-0 bg-gray-500 opacity-75" | 					class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|           data-id="modal_backdrop" | 					data-id="modal_backdrop" | ||||||
|         /> | 				/> | ||||||
|       </div> | 			</div> | ||||||
|       <span | 			<span | ||||||
|         class="hidden sm:inline-block sm:align-middle sm:h-screen" | 				class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|         aria-hidden="true">​</span | 				aria-hidden="true">​</span | ||||||
|       > | 			> | ||||||
|       <div | 			<div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" | 				class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" | 				role="dialog" | ||||||
|         aria-modal="true" | 				aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" | 				aria-labelledby="modal-headline" | ||||||
|       > | 			> | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> | 				<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> | 					<div class=""> | ||||||
|             <div | 						<div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | 							class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > | 						> | ||||||
|               <svg | 							<svg | ||||||
|                 class="h-6 w-6 text-blue-600" | 								class="h-6 w-6 text-blue-600" | ||||||
|                 fill="currentColor" | 								fill="currentColor" | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 								xmlns="http://www.w3.org/2000/svg" | ||||||
|                 viewBox="0 0 24 24" | 								viewBox="0 0 24 24" | ||||||
|                 ><path fill="none" d="M0 0h24v24H0z" /><path | 								><path fill="none" d="M0 0h24v24H0z" /><path | ||||||
|                   d="M9.33 11.5h2.17A4.5 4.5 0 0116 16H9v1h8v-1a5.58 5.58 0 00-.89-3H19a5 5 0 014.52 2.85A13.15 13.15 0 0113 21c-2.76 0-5.1-.59-7-1.63v-9.3a6.97 6.97 0 013.33 1.43zM5 19a1 1 0 01-1 1H2a1 1 0 01-1-1v-9a1 1 0 011-1h2a1 1 0 011 1v9zM18 5a3 3 0 110 6 3 3 0 010-6zm-7-3a3 3 0 110 6 3 3 0 010-6z" | 									d="M9.33 11.5h2.17A4.5 4.5 0 0116 16H9v1h8v-1a5.58 5.58 0 00-.89-3H19a5 5 0 014.52 2.85A13.15 13.15 0 0113 21c-2.76 0-5.1-.59-7-1.63v-9.3a6.97 6.97 0 013.33 1.43zM5 19a1 1 0 01-1 1H2a1 1 0 01-1-1v-9a1 1 0 011-1h2a1 1 0 011 1v9zM18 5a3 3 0 110 6 3 3 0 010-6zm-7-3a3 3 0 110 6 3 3 0 010-6z" | ||||||
|                 /></svg | 								/></svg | ||||||
|               > | 							> | ||||||
|             </div> | 						</div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> | 						<div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> | 							<h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("attention")} | 								{$_( | ||||||
|               </h3> | 									"do-you-want-to-delete-this-donor-with-all-related-donations" | ||||||
|               <div class="mt-2 mb-6"> | 								)} | ||||||
|                 <p class="text-sm text-gray-500"> | 							</h3> | ||||||
|                   {$_( | 							<div class="mb-6"> | ||||||
|                     "do-you-want-to-delete-this-donor-with-all-related-donations" | 								<p class="text-sm text-gray-500"> | ||||||
|                   )} | 									{$_("all-associated-donations-will-get-deleted-as-well")} | ||||||
|                   <br /> | 								</p> | ||||||
|                   {$_("all-associated-donations-will-get-deleted-as-well")} | 							</div> | ||||||
|                 </p> | 						</div> | ||||||
|               </div> | 					</div> | ||||||
|             </div> | 				</div> | ||||||
|           </div> | 				<div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|         </div> | 					<button | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> | 						on:click={deleteDonor} | ||||||
|           <button | 						type="button" | ||||||
|             on:click={deleteDonor} | 						class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500" | ||||||
|             type="button" | 					> | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm" | 						{$_("confirm-delete-donor-with-all-donations")} | ||||||
|           > | 					</button> | ||||||
|             {$_("confirm-delete-donor-with-all-donations")} | 					<button | ||||||
|           </button> | 						on:click={cancelDelete} | ||||||
|           <button | 						type="button" | ||||||
|             on:click={cancelDelete} | 						class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|             type="button" | 					> | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" | 						{$_("cancel-keep-donor")} | ||||||
|           > | 					</button> | ||||||
|             {$_("cancel-keep-donor")} | 				</div> | ||||||
|           </button> | 			</div> | ||||||
|         </div> | 		</div> | ||||||
|       </div> | 	</div> | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -1,437 +1,413 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { DonorService } from "@odit/lfk-client-js"; | ||||||
|   import store from "../../store"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import { DonorService, DonationService } from "@odit/lfk-client-js"; | 	import store from "../../store"; | ||||||
|  | 	import toast from "svelte-french-toast"; | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; | 	import isEmail from "validator/es/lib/isEmail"; | ||||||
|   import isEmail from "validator/es/lib/isEmail"; | 	import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   import ConfirmDonorDeletion from "./ConfirmDonorDeletion.svelte"; | 	let data_loaded = false; | ||||||
|   let data_loaded = false; | 	export let params; | ||||||
|   export let params; | 	$: delete_triggered = false; | ||||||
|   $: delete_triggered = false; | 	$: original_data = {}; | ||||||
|   $: original_data = {}; | 	$: editable = {}; | ||||||
|   $: editable = {}; | 	$: changes_performed = !( | ||||||
|   $: current_donations = []; | 		JSON.stringify(original_data) === JSON.stringify(editable) | ||||||
|   $: changes_performed = !( | 	); | ||||||
|     JSON.stringify(original_data) === JSON.stringify(editable) | 	$: isEmailValid = | ||||||
|   ); | 		(editable.email || "") === "" || | ||||||
|   $: isEmailValid = | 		(editable.email && isEmail(editable.email || "")); | ||||||
|     (editable.email || "") === "" || | 	$: isFirstnameValid = editable.firstname !== ""; | ||||||
|     (editable.email && isEmail(editable.email || "")); | 	$: isLastnameValid = editable.lastname !== ""; | ||||||
|   $: isFirstnameValid = editable.firstname !== ""; | 	$: save_enabled = | ||||||
|   $: isLastnameValid = editable.lastname !== ""; | 		changes_performed && | ||||||
|   $: save_enabled = | 		isFirstnameValid && | ||||||
|     changes_performed && | 		isLastnameValid && | ||||||
|     isFirstnameValid && | 		isEmailValid && | ||||||
|     isLastnameValid && | 		isPhoneValidOrEmpty && | ||||||
|     isEmailValid && | 		((isAddress1Valid && iszipcodevalid && iscityvalid) || | ||||||
|     isPhoneValidOrEmpty && | 			editable.address_checked === false); | ||||||
|     ((isAddress1Valid && iszipcodevalid && iscityvalid) || | 	const promise = DonorService.donorControllerGetOne(params.donorid).then( | ||||||
|       editable.address_checked === false); | 		(data) => { | ||||||
|   const donation_promise = DonationService.donationControllerGetAll().then( | 			data_loaded = true; | ||||||
|     (val) => { | 			original_data = Object.assign(original_data, data); | ||||||
|       current_donations = val; | 			editable = Object.assign(editable, original_data); | ||||||
|     } | 			editable.address_checked = editable.address.address1 !== null; | ||||||
|   ); | 			original_data.address_checked = editable.address.address1 !== null; | ||||||
|   const promise = DonorService.donorControllerGetOne(params.donorid).then( | 			if (editable.address_checked === false) { | ||||||
|     (data) => { | 				editable.address = { | ||||||
|       data_loaded = true; | 					address1: "", | ||||||
|       original_data = Object.assign(original_data, data); | 					address2: "", | ||||||
|       editable = Object.assign(editable, original_data); | 					city: "", | ||||||
|       editable.address_checked = editable.address.address1 !== null; | 					postalcode: "", | ||||||
|       original_data.address_checked = editable.address.address1 !== null; | 					country: "", | ||||||
|       if (editable.address_checked === false) { | 				}; | ||||||
|         editable.address = { | 			} | ||||||
|           address1: "", | 		} | ||||||
|           address2: "", | 	); | ||||||
|           city: "", | 	$: isPhoneValidOrEmpty = | ||||||
|           postalcode: "", | 		editable.phone?.includes("+") || | ||||||
|           country: "", | 		editable.phone === "" || | ||||||
|         }; | 		editable.phone === null; | ||||||
|       } | 	$: isAddress1Valid = editable.address?.address1?.trim().length !== 0; | ||||||
|     } | 	$: iszipcodevalid = editable.address?.postalcode?.trim().length !== 0; | ||||||
|   ); | 	$: iscityvalid = editable.address?.city?.trim().length !== 0; | ||||||
|   $: isPhoneValidOrEmpty = | 	function submit() { | ||||||
|     editable.phone?.includes("+") || | 		if (data_loaded === true && save_enabled) { | ||||||
|     editable.phone === "" || | 			toast($_("donor-is-being-updated")); | ||||||
|     editable.phone === null; | 			editable.address.country = "DE"; | ||||||
|   $: isAddress1Valid = editable.address?.address1?.trim().length !== 0; | 			if (editable.address_checked === false) { | ||||||
|   $: iszipcodevalid = editable.address?.postalcode?.trim().length !== 0; | 				editable.address = null; | ||||||
|   $: iscityvalid = editable.address?.city?.trim().length !== 0; | 			} | ||||||
|   let modal_open = false; | 			if (editable.email) editable.email = editable.email; | ||||||
|   let delete_donor = {}; | 			else editable.email = null; | ||||||
|   function submit() { | 			if (editable.phone) editable.phone = editable.phone; | ||||||
|     if (data_loaded === true && save_enabled) { | 			else editable.phone = null; | ||||||
|       toast($_("donor-is-being-updated")); | 			if (editable.middlename) editable.middlename = editable.middlename; | ||||||
|       editable.address.country = "DE"; | 			editable.receiptNeeded = editable.address_checked; | ||||||
|       if (editable.address_checked === false) { | 			DonorService.donorControllerPut(original_data.id, editable) | ||||||
|         editable.address = null; | 				.then((resp) => { | ||||||
|       } | 					Object.assign(original_data, editable); | ||||||
|       if (editable.email) editable.email = editable.email; | 					original_data = original_data; | ||||||
|       if (editable.phone) editable.phone = editable.phone; | 					toast.success($_("updated-donor")); | ||||||
|       if (editable.middlename) editable.middlename = editable.middlename; | 				}) | ||||||
|       editable.receiptNeeded = editable.address_checked; | 				.catch((err) => {}); | ||||||
|       DonorService.donorControllerPut(original_data.id, editable) | 		} else { | ||||||
|         .then((resp) => { | 		} | ||||||
|           Object.assign(original_data, editable); | 	} | ||||||
|           original_data = original_data; | 	function deleteDonor() { | ||||||
|           toast.success($_("updated-donor")); | 		DonorService.donorControllerRemove(original_data.id, true) | ||||||
|         }) | 			.then((resp) => { | ||||||
|         .catch((err) => {}); | 				toast.success($_("donor-deleted")); | ||||||
|     } else { | 				location.replace("./"); | ||||||
|     } | 			}) | ||||||
|   } | 			.catch((err) => { | ||||||
|   function deleteDonor() { | 				console.log(err); | ||||||
|     DonorService.donorControllerRemove(original_data.id, false) | 			}); | ||||||
|       .then((resp) => { | 	} | ||||||
|         toast($_("donor-deleted")); |  | ||||||
|         location.replace("./"); |  | ||||||
|       }) |  | ||||||
|       .catch((err) => { |  | ||||||
|         modal_open = true; |  | ||||||
|         delete_donor = original_data; |  | ||||||
|       }); |  | ||||||
|   } |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <ConfirmDonorDeletion bind:modal_open bind:delete_donor /> | {#await promise} | ||||||
| {#await promise && donation_promise} | 	{$_("loading-donor-details")} | ||||||
|   {$_("loading-donor-details")} |  | ||||||
| {:then} | {:then} | ||||||
|   <section class="container p-5 select-none"> | 	<section class="container p-5 select-none"> | ||||||
|     <div class="flex flex-row mb-4"> | 		<div class="flex flex-row mb-4"> | ||||||
|       <div class="w-full"> | 			<div class="w-full"> | ||||||
|         <nav class="w-full flex"> | 				<nav class="w-full flex"> | ||||||
|           <ol class="list-none flex flex-row items-center justify-start"> | 					<ol class="list-none flex flex-row items-center justify-start"> | ||||||
|             <li class="flex items-center"> | 						<li class="flex items-center"> | ||||||
|               <svg | 							<a class="mr-2" href="./" | ||||||
|                 fill="currentColor" | 								><svg | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 									xmlns="http://www.w3.org/2000/svg" | ||||||
|                 viewBox="0 0 24 24" | 									width="24" | ||||||
|                 width="24" | 									height="24" | ||||||
|                 height="24" | 									viewBox="0 0 24 24" | ||||||
|                 ><path fill="none" d="M0 0h24v24H0z" /> | 									fill="none" | ||||||
|                 <path | 									stroke="currentColor" | ||||||
|                   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" | 									stroke-width="2" | ||||||
|                 /></svg | 									stroke-linecap="round" | ||||||
|               > | 									stroke-linejoin="round" | ||||||
|             </li> | 									class="inline-block" | ||||||
|             <li class="flex items-center ml-2"> | 									><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg | ||||||
|               <a class="mr-2" href="./">{$_("donors")}</a><svg | 								> | ||||||
|                 stroke="currentColor" | 								{$_("donors")}</a | ||||||
|                 fill="none" | 							> | ||||||
|                 stroke-width="2" | 						</li> | ||||||
|                 viewBox="0 0 24 24" | 					</ol> | ||||||
|                 stroke-linecap="round" | 				</nav> | ||||||
|                 stroke-linejoin="round" | 			</div> | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" | 		</div> | ||||||
|                 height="1em" | 		<div class="mb-4 text-3xl font-extrabold leading-tight"> | ||||||
|                 width="1em" | 			{original_data.firstname} | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 			{original_data.middlename || ""} | ||||||
|                 ><line x1="5" y1="12" x2="19" y2="12" /> | 			{original_data.lastname} | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg | 			<div data-id="donor_actions_${editable.id}"> | ||||||
|               > | 				{#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:DELETE")} | ||||||
|             </li> | 					{#if delete_triggered} | ||||||
|             <li class="flex items-center"> | 						<button | ||||||
|               <span class="mr-2" | 							on:click={deleteDonor} | ||||||
|                 >{original_data.firstname} | 							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:w-auto sm:text-sm" | ||||||
|                 {original_data.middlename || ""} | 							>{$_("confirm-deletion")}</button | ||||||
|                 {original_data.lastname}</span | 						> | ||||||
|               > | 						<button | ||||||
|             </li> | 							on:click={() => { | ||||||
|           </ol> | 								delete_triggered = !delete_triggered; | ||||||
|         </nav> | 							}} | ||||||
|       </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" | ||||||
|     </div> | 							>{$_("cancel")}</button | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> | 						> | ||||||
|       {original_data.firstname} | 					{/if} | ||||||
|       {original_data.middlename || ""} | 					{#if !delete_triggered} | ||||||
|       {original_data.lastname} | 						<button | ||||||
|       <span data-id="donor_actions_${editable.id}"> | 							on:click={() => { | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:DELETE")} | 								delete_triggered = true; | ||||||
|           {#if delete_triggered} | 							}} | ||||||
|             <button | 							type="button" | ||||||
|               on:click={deleteDonor} | 							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:w-auto sm:text-sm" | ||||||
|               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:" | 							>{$_("delete-donor")}</button | ||||||
|               >{$_("confirm-deletion")}</button | 						> | ||||||
|             > | 					{/if} | ||||||
|             <button | 				{/if} | ||||||
|               on:click={() => { | 				{#if !delete_triggered} | ||||||
|                 delete_triggered = !delete_triggered; | 					<button | ||||||
|               }} | 						disabled={!save_enabled} | ||||||
|               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:" | 						class:opacity-50={!save_enabled} | ||||||
|               >{$_("cancel")}</button | 						type="button" | ||||||
|             > | 						on:click={submit} | ||||||
|           {/if} | 						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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|           {#if !delete_triggered} | 						>{$_("save-changes")}</button | ||||||
|             <button | 					> | ||||||
|               on:click={() => { | 				{/if} | ||||||
|                 delete_triggered = true; | 			</div> | ||||||
|               }} | 		</div> | ||||||
|               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:" | 		<div> | ||||||
|               >{$_("delete-donor")}</button | 			<span class="font-semibold text-gray-700" | ||||||
|             > | 				>{$_("total-donation-amount")}:</span | ||||||
|           {/if} | 			> | ||||||
|         {/if} | 			<span | ||||||
|         {#if !delete_triggered} | 				>{(editable.donationAmount / 100) | ||||||
|           <button | 					.toFixed(2) | ||||||
|             disabled={!save_enabled} | 					.toLocaleString("de-DE", { valute: "EUR" })}€</span | ||||||
|             class:opacity-50={!save_enabled} | 			> | ||||||
|             type="button" | 			| | ||||||
|             on:click={submit} | 			<span class="font-semibold text-gray-700">{$_("total-paid-amount")}:</span | ||||||
|             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:" | 			> | ||||||
|             >{$_("save-changes")}</button | 			<span | ||||||
|           > | 				>{(editable.paidDonationAmount / 100) | ||||||
|         {/if} | 					.toFixed(2) | ||||||
|       </span> | 					.toLocaleString("de-DE", { valute: "EUR" })}€</span | ||||||
|     </div> | 			> | ||||||
|     <!--  --> | 			<br /> | ||||||
|     <div> | 			<span class="font-semibold text-gray-700">{$_("donations")}:</span> | ||||||
|       <span class="font-medium text-gray-700" | 			{#if original_data.donations.length > 0} | ||||||
|         >{$_("total-donation-amount")}:</span | 				{#each original_data.donations as d} | ||||||
|       > | 					{#if d.responseType === "DISTANCEDONATION"} | ||||||
|       <span | 						<a | ||||||
|         >{(editable.donationAmount / 100) | 							href="../donations/{d.id}" | ||||||
|           .toFixed(2) | 							class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-600 text-white mr-1" | ||||||
|           .toLocaleString("de-DE", { valute: "EUR" })}€</span | 							>{d.runner.firstname} | ||||||
|       > | 							{d.runner.middlename || ""} | ||||||
|       | | 							{d.runner.lastname}</a | ||||||
|       <span class="font-medium text-gray-700">{$_("total-paid-amount")}:</span> | 						> | ||||||
|       <span | 					{:else} | ||||||
|         >{(editable.paidDonationAmount / 100) | 						<a | ||||||
|           .toFixed(2) | 							href="../donations/{d.id}" | ||||||
|           .toLocaleString("de-DE", { valute: "EUR" })}€</span | 							class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-700 text-white mr-1" | ||||||
|       > | 							>{$_("fixed-donation")}: | ||||||
|       <br /> | 							{(d.amount / 100) | ||||||
|       <span class="font-medium text-gray-700">{$_("donations")}:</span> | 								.toFixed(2) | ||||||
|       {#if current_donations.filter((d) => d.donor.id == editable.id).length > 0} | 								.toLocaleString("de-DE", { valute: "EUR" })}€</a | ||||||
|         {#each current_donations.filter((o) => o.donor.id == editable.id) as d} | 						> | ||||||
|           {#if d.responseType === "DISTANCEDONATION"} | 					{/if} | ||||||
|             <a | 				{/each} | ||||||
|               href="../donations/{d.id}" | 			{:else}{$_("donor-has-no-associated-donations")}{/if} | ||||||
|               class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-600 text-white mr-1" | 		</div> | ||||||
|               >{d.runner.firstname} | 		<div class="mt-2 w-full"> | ||||||
|               {d.runner.middlename || ""} | 			<label for="firstname" class="font-semibold text-gray-700" | ||||||
|               {d.runner.lastname}</a | 				>{$_("first-name")}</label | ||||||
|             > | 			> | ||||||
|           {:else} | 			<input | ||||||
|             <a | 				autocomplete="off" | ||||||
|               href="../donations/{d.id}" | 				placeholder={$_("first-name")} | ||||||
|               class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-700 text-white mr-1" | 				type="text" | ||||||
|               >{$_("fixed-donation")}: | 				class:border-red-500={!isFirstnameValid} | ||||||
|               {(d.amount / 100) | 				class:focus:border-red-500={!isFirstnameValid} | ||||||
|                 .toFixed(2) | 				class:focus:ring-red-500={!isFirstnameValid} | ||||||
|                 .toLocaleString("de-DE", { valute: "EUR" })}€</a | 				bind:value={editable.firstname} | ||||||
|             > | 				name="firstname" | ||||||
|           {/if} | 				class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|         {/each} | 			/> | ||||||
|       {:else}{$_("donor-has-no-associated-donations")}{/if} | 			{#if !isFirstnameValid} | ||||||
|     </div> | 				<span | ||||||
|     <div class=" w-full"> | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|       <label for="firstname" class="font-medium text-gray-700" | 				> | ||||||
|         >{$_("first-name")}</label | 					{$_("first-name-is-required")} | ||||||
|       > | 				</span> | ||||||
|       <input | 			{/if} | ||||||
|         autocomplete="off" | 		</div> | ||||||
|         placeholder={$_("first-name")} | 		<div class="mt-2 w-full"> | ||||||
|         type="text" | 			<label for="middlename" class="font-semibold text-gray-700" | ||||||
|         class:border-red-500={!isFirstnameValid} | 				>{$_("middle-name")}</label | ||||||
|         class:focus:border-red-500={!isFirstnameValid} | 			> | ||||||
|         class:focus:ring-red-500={!isFirstnameValid} | 			<input | ||||||
|         bind:value={editable.firstname} | 				autocomplete="off" | ||||||
|         name="firstname" | 				placeholder={$_("middle-name")} | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 				type="text" | ||||||
|       /> | 				bind:value={editable.middlename} | ||||||
|       {#if !isFirstnameValid} | 				name="middlename" | ||||||
|         <span | 				class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 			/> | ||||||
|         > | 		</div> | ||||||
|           {$_("first-name-is-required")} | 		<div class="mt-2 w-full"> | ||||||
|         </span> | 			<label for="lastname" class="font-semibold text-gray-700" | ||||||
|       {/if} | 				>{$_("last-name")}</label | ||||||
|     </div> | 			> | ||||||
|     <div class=" w-full"> | 			<input | ||||||
|       <label for="middlename" class="font-medium text-gray-700" | 				autocomplete="off" | ||||||
|         >{$_("middle-name")}</label | 				placeholder={$_("last-name")} | ||||||
|       > | 				type="text" | ||||||
|       <input | 				bind:value={editable.lastname} | ||||||
|         autocomplete="off" | 				class:border-red-500={!isLastnameValid} | ||||||
|         placeholder={$_("middle-name")} | 				class:focus:border-red-500={!isLastnameValid} | ||||||
|         type="text" | 				class:focus:ring-red-500={!isLastnameValid} | ||||||
|         bind:value={editable.middlename} | 				name="lastname" | ||||||
|         name="middlename" | 				class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 			/> | ||||||
|       /> | 			{#if !isLastnameValid} | ||||||
|     </div> | 				<span | ||||||
|     <div class=" w-full"> | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|       <label for="lastname" class="font-medium text-gray-700" | 				> | ||||||
|         >{$_("last-name")}</label | 					{$_("last-name-is-required")} | ||||||
|       > | 				</span> | ||||||
|       <input | 			{/if} | ||||||
|         autocomplete="off" | 		</div> | ||||||
|         placeholder={$_("last-name")} | 		<div class="mt-2 w-full"> | ||||||
|         type="text" | 			<label for="email" class="font-semibold text-gray-700" | ||||||
|         bind:value={editable.lastname} | 				>{$_("e-mail-adress")}</label | ||||||
|         class:border-red-500={!isLastnameValid} | 			> | ||||||
|         class:focus:border-red-500={!isLastnameValid} | 			<input | ||||||
|         class:focus:ring-red-500={!isLastnameValid} | 				autocomplete="off" | ||||||
|         name="lastname" | 				placeholder={$_("e-mail-adress")} | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 				type="email" | ||||||
|       /> | 				bind:value={editable.email} | ||||||
|       {#if !isLastnameValid} | 				class:border-red-500={!isEmailValid} | ||||||
|         <span | 				class:focus:border-red-500={!isEmailValid} | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 				class:focus:ring-red-500={!isEmailValid} | ||||||
|         > | 				name="email" | ||||||
|           {$_("last-name-is-required")} | 				class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|         </span> | 			/> | ||||||
|       {/if} | 			{#if !isEmailValid} | ||||||
|     </div> | 				<span | ||||||
|     <div class=" w-full"> | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|       <label for="email" class="font-medium text-gray-700" | 				> | ||||||
|         >{$_("e-mail-adress")}</label | 					{$_("valid-email-is-required")} | ||||||
|       > | 				</span> | ||||||
|       <input | 			{/if} | ||||||
|         autocomplete="off" | 		</div> | ||||||
|         placeholder={$_("e-mail-adress")} | 		<div class="mt-2 w-full"> | ||||||
|         type="email" | 			<label for="phone" class="font-semibold text-gray-700" | ||||||
|         bind:value={editable.email} | 				>{$_("phone")}</label | ||||||
|         class:border-red-500={!isEmailValid} | 			> | ||||||
|         class:focus:border-red-500={!isEmailValid} | 			<input | ||||||
|         class:focus:ring-red-500={!isEmailValid} | 				autocomplete="off" | ||||||
|         name="email" | 				placeholder={$_("phone")} | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 				type="tel" | ||||||
|       /> | 				class:border-red-500={!isPhoneValidOrEmpty} | ||||||
|       {#if !isEmailValid} | 				class:focus:border-red-500={!isPhoneValidOrEmpty} | ||||||
|         <span | 				class:focus:ring-red-500={!isPhoneValidOrEmpty} | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 				bind:value={editable.phone} | ||||||
|         > | 				name="phone" | ||||||
|           {$_("valid-email-is-required")} | 				class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|         </span> | 			/> | ||||||
|       {/if} | 			{#if !isPhoneValidOrEmpty} | ||||||
|     </div> | 				<span | ||||||
|     <div class=" w-full"> | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|       <label for="phone" class="font-medium text-gray-700">{$_("phone")}</label> | 				> | ||||||
|       <input | 					{$_("valid-international-phone-number-is-required")} | ||||||
|         autocomplete="off" | 				</span> | ||||||
|         placeholder={$_("phone")} | 			{/if} | ||||||
|         type="tel" | 		</div> | ||||||
|         class:border-red-500={!isPhoneValidOrEmpty} | 		<div class="flex items-start mt-2"> | ||||||
|         class:focus:border-red-500={!isPhoneValidOrEmpty} | 			<div class="flex items-center h-5"> | ||||||
|         class:focus:ring-red-500={!isPhoneValidOrEmpty} | 				<input | ||||||
|         bind:value={editable.phone} | 					bind:checked={editable.address_checked} | ||||||
|         name="phone" | 					id="comments" | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 					name="comments" | ||||||
|       /> | 					type="checkbox" | ||||||
|       {#if !isPhoneValidOrEmpty} | 					class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||||||
|         <span | 				/> | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 			</div> | ||||||
|         > | 			<div class="ml-3"> | ||||||
|           {$_("valid-international-phone-number-is-required")} | 				<label for="comments" class="font-semibold text-gray-700" | ||||||
|         </span> | 					>{$_("receipt-needed")}</label | ||||||
|       {/if} | 				> | ||||||
|     </div> | 			</div> | ||||||
|     <div class="flex items-start mt-2"> | 		</div> | ||||||
|       <div class="flex items-center h-5"> | 		{#if editable.address_checked === true} | ||||||
|         <input | 			<div class="col-span-6"> | ||||||
|           bind:checked={editable.address_checked} | 				<label for="address1" class="block font-medium text-gray-700" | ||||||
|           id="comments" | 					>{$_("address")}</label | ||||||
|           name="comments" | 				> | ||||||
|           type="checkbox" | 				<input | ||||||
|           class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | 					autocomplete="off" | ||||||
|         /> | 					placeholder="Address" | ||||||
|       </div> | 					class:border-red-500={!isAddress1Valid} | ||||||
|       <div class="ml-3"> | 					class:focus:border-red-500={!isAddress1Valid} | ||||||
|         <label for="comments" class="font-medium text-gray-700" | 					class:focus:ring-red-500={!isAddress1Valid} | ||||||
|           >{$_("receipt-needed")}</label | 					bind:value={editable.address.address1} | ||||||
|         > | 					type="text" | ||||||
|       </div> | 					name="address1" | ||||||
|     </div> | 					class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|     {#if editable.address_checked === true} | 				/> | ||||||
|       <div class="col-span-6"> | 				{#if !isAddress1Valid} | ||||||
|         <label for="address1" class="block font-medium text-gray-700" | 					<span | ||||||
|           >{$_("address")}</label | 						class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|         > | 					> | ||||||
|         <input | 						{$_("address-is-required")} | ||||||
|           autocomplete="off" | 					</span> | ||||||
|           placeholder="Address" | 				{/if} | ||||||
|           class:border-red-500={!isAddress1Valid} | 			</div> | ||||||
|           class:focus:border-red-500={!isAddress1Valid} | 			<div class="col-span-6"> | ||||||
|           class:focus:ring-red-500={!isAddress1Valid} | 				<label for="address2" class="block font-medium text-gray-700" | ||||||
|           bind:value={editable.address.address1} | 					>{$_("apartment-suite-etc")}</label | ||||||
|           type="text" | 				> | ||||||
|           name="address1" | 				<input | ||||||
|           class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 					autocomplete="off" | ||||||
|         /> | 					placeholder={$_("apartment-suite-etc")} | ||||||
|         {#if !isAddress1Valid} | 					bind:value={editable.address.address2} | ||||||
|           <span | 					type="text" | ||||||
|             class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 					name="address2" | ||||||
|           > | 					class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|             {$_("address-is-required")} | 				/> | ||||||
|           </span> | 			</div> | ||||||
|         {/if} | 			<div class="col-span-6"> | ||||||
|       </div> | 				<label for="zipcode" class="block font-medium text-gray-700" | ||||||
|       <div class="col-span-6"> | 					>{$_("zip-postal-code")}</label | ||||||
|         <label for="address2" class="block font-medium text-gray-700" | 				> | ||||||
|           >{$_("apartment-suite-etc")}</label | 				<input | ||||||
|         > | 					autocomplete="off" | ||||||
|         <input | 					placeholder={$_("zip-postal-code")} | ||||||
|           autocomplete="off" | 					class:border-red-500={!iszipcodevalid} | ||||||
|           placeholder={$_("apartment-suite-etc")} | 					class:focus:border-red-500={!iszipcodevalid} | ||||||
|           bind:value={editable.address.address2} | 					class:focus:ring-red-500={!iszipcodevalid} | ||||||
|           type="text" | 					bind:value={editable.address.postalcode} | ||||||
|           name="address2" | 					type="text" | ||||||
|           class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 					name="zipcode" | ||||||
|         /> | 					class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|       </div> | 				/> | ||||||
|       <div class="col-span-6"> | 				{#if !iszipcodevalid} | ||||||
|         <label for="zipcode" class="block font-medium text-gray-700" | 					<span | ||||||
|           >{$_("zip-postal-code")}</label | 						class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|         > | 					> | ||||||
|         <input | 						{$_("valid-zipcode-postal-code-is-required")} | ||||||
|           autocomplete="off" | 					</span> | ||||||
|           placeholder={$_("zip-postal-code")} | 				{/if} | ||||||
|           class:border-red-500={!iszipcodevalid} | 			</div> | ||||||
|           class:focus:border-red-500={!iszipcodevalid} | 			<div class="col-span-6"> | ||||||
|           class:focus:ring-red-500={!iszipcodevalid} | 				<label for="city" class="block font-medium text-gray-700" | ||||||
|           bind:value={editable.address.postalcode} | 					>{$_("city")}</label | ||||||
|           type="text" | 				> | ||||||
|           name="zipcode" | 				<input | ||||||
|           class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 					autocomplete="off" | ||||||
|         /> | 					placeholder={$_("city")} | ||||||
|         {#if !iszipcodevalid} | 					class:border-red-500={!iscityvalid} | ||||||
|           <span | 					class:focus:border-red-500={!iscityvalid} | ||||||
|             class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 					class:focus:ring-red-500={!iscityvalid} | ||||||
|           > | 					bind:value={editable.address.city} | ||||||
|             {$_("valid-zipcode-postal-code-is-required")} | 					type="text" | ||||||
|           </span> | 					name="city" | ||||||
|         {/if} | 					class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|       </div> | 				/> | ||||||
|       <div class="col-span-6"> | 				{#if !iscityvalid} | ||||||
|         <label for="city" class="block font-medium text-gray-700" | 					<span | ||||||
|           >{$_("city")}</label | 						class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|         > | 					> | ||||||
|         <input | 						{$_("valid-city-is-required")} | ||||||
|           autocomplete="off" | 					</span> | ||||||
|           placeholder={$_("city")} | 				{/if} | ||||||
|           class:border-red-500={!iscityvalid} | 			</div> | ||||||
|           class:focus:border-red-500={!iscityvalid} | 		{/if} | ||||||
|           class:focus:ring-red-500={!iscityvalid} | 	</section> | ||||||
|           bind:value={editable.address.city} |  | ||||||
|           type="text" |  | ||||||
|           name="city" |  | ||||||
|           class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |  | ||||||
|         /> |  | ||||||
|         {#if !iscityvalid} |  | ||||||
|           <span |  | ||||||
|             class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" |  | ||||||
|           > |  | ||||||
|             {$_("valid-city-is-required")} |  | ||||||
|           </span> |  | ||||||
|         {/if} |  | ||||||
|       </div> |  | ||||||
|     {/if} |  | ||||||
|   </section> |  | ||||||
| {:catch error} | {:catch error} | ||||||
|   <PromiseError {error} /> | 	<PromiseError {error} /> | ||||||
| {/await} | {/await} | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ | |||||||
|     {:else} |     {:else} | ||||||
|       <a |       <a | ||||||
|         href="../donations/{donation.id}" |         href="../donations/{donation.id}" | ||||||
|         class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-700 text-white mr-1" |         class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-700 text-white mr-1" | ||||||
|         >{$_("fixed-donation")}: |         >{$_("fixed-donation")}: | ||||||
|         {(donation.amount / 100) |         {(donation.amount / 100) | ||||||
|           .toFixed(2) |           .toFixed(2) | ||||||
|   | |||||||
| @@ -9,61 +9,61 @@ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> |   <h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_("donors")} |     {$_("donors")} | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:CREATE")} |   </h4> | ||||||
|       <button |   {#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:CREATE")} | ||||||
|         on:click={() => { |     <button | ||||||
|           modal_open = true; |       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" |       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:w-auto sm:text-sm  mb-1 lg:mb-0" | ||||||
|         {$_("add-donor")} |     > | ||||||
|       </button> |       {$_("add-donor")} | ||||||
|     {/if} |     </button> | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:GET")} |   {/if} | ||||||
|       <button |   {#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:GET")} | ||||||
|         on:click={() => { |     <button | ||||||
|           const data = current_donors |       on:click={() => { | ||||||
|             .filter((d) => d.receiptNeeded === true) |         const data = current_donors | ||||||
|             .map(function (d) { |           .filter((d) => d.receiptNeeded === true) | ||||||
|               d.address.address2 = |           .map(function (d) { | ||||||
|                 d.address.address2 === "" ? "" : " " + d.address.address2; |             d.address.address2 = | ||||||
|               const address = `${d.address.address1}${d.address.address2}, ${d.address.postalcode} ${d.address.city}, ${d.address.country}`; |               d.address.address2 === "" ? "" : " " + d.address.address2; | ||||||
|               return [ |             const address = `${d.address.address1}${d.address.address2}, ${d.address.postalcode} ${d.address.city}, ${d.address.country}`; | ||||||
|                 d.firstname, |             return [ | ||||||
|                 d.middlename, |               d.firstname, | ||||||
|                 d.lastname, |               d.middlename, | ||||||
|                 d.paidDonationAmount, |               d.lastname, | ||||||
|                 address, |               (d.paidDonationAmount/100).toFixed(2), | ||||||
|               ]; |               address, | ||||||
|             }); |             ]; | ||||||
|           let csv = `${$_("csv_import__firstname")};${$_( |  | ||||||
|             "csv_import__middlename" |  | ||||||
|           )};${$_("csv_import__lastname")};${$_( |  | ||||||
|             "total_donation_amount_in_eur" |  | ||||||
|           )};${$_("address")}\n`; |  | ||||||
|           data.forEach(function (row) { |  | ||||||
|             csv += row.join(";"); |  | ||||||
|             csv += "\n"; |  | ||||||
|           }); |           }); | ||||||
|           let hiddenElement = document.createElement("a"); |         let csv = `${$_("csv_import__firstname")};${$_( | ||||||
|           hiddenElement.href = "data:text/csv;charset=utf-8," + encodeURI(csv); |           "csv_import__middlename" | ||||||
|           hiddenElement.target = "_blank"; |         )};${$_("csv_import__lastname")};${$_( | ||||||
|           hiddenElement.download = `${$_( |           "total_donation_amount_in_eur" | ||||||
|             "filename_sponsoringquittungsliste" |         )};${$_("address")}\n`; | ||||||
|           )}.csv`; |         data.forEach(function (row) { | ||||||
|           hiddenElement.click(); |           csv += row.join(";"); | ||||||
|           hiddenElement.remove(); |           csv += "\n"; | ||||||
|         }} |         }); | ||||||
|         type="button" |         let hiddenElement = document.createElement("a"); | ||||||
|         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" |         hiddenElement.href = "data:text/csv;charset=utf-8," + encodeURI(csv); | ||||||
|       > |         hiddenElement.target = "_blank"; | ||||||
|         {$_("sponsoring-quittungs-liste_herunterladen")} |         hiddenElement.download = `${$_( | ||||||
|       </button> |           "filename_sponsoringquittungsliste" | ||||||
|     {/if} |         )}.csv`; | ||||||
|   </span> |         hiddenElement.click(); | ||||||
|  |         hiddenElement.remove(); | ||||||
|  |       }} | ||||||
|  |       type="button" | ||||||
|  |       class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:w-auto sm:text-sm  mb-1 lg:mb-0" | ||||||
|  |     > | ||||||
|  |       {$_("sponsoring-quittungs-liste_herunterladen")} | ||||||
|  |     </button> | ||||||
|  |   {/if} | ||||||
|   <DonorsOverview bind:current_donors bind:addDonors /> |   <DonorsOverview bind:current_donors bind:addDonors /> | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -147,7 +147,7 @@ | |||||||
|  |  | ||||||
|   onMount(async () => { |   onMount(async () => { | ||||||
|     let page = 0; |     let page = 0; | ||||||
|     let pagesize = 100; |     let pagesize = 300; | ||||||
|     while (page >= 0) { |     while (page >= 0) { | ||||||
|       const donors = await DonorService.donorControllerGetAll(page, pagesize); |       const donors = await DonorService.donorControllerGetAll(page, pagesize); | ||||||
|       if (donors.length == 0) { |       if (donors.length == 0) { | ||||||
| @@ -162,7 +162,6 @@ | |||||||
|  |  | ||||||
|       dataLoaded = true; |       dataLoaded = true; | ||||||
|       page++; |       page++; | ||||||
|       pagesize += 100; |  | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| </script> | </script> | ||||||
| @@ -175,7 +174,7 @@ | |||||||
|     toast.loading($_("deleting-donor")); |     toast.loading($_("deleting-donor")); | ||||||
|     await DonorService.donorControllerRemove(event.detail.id, true); |     await DonorService.donorControllerRemove(event.detail.id, true); | ||||||
|     toast.dismiss(); |     toast.dismiss(); | ||||||
|     toast($_("donor-deleted")); |     toast.success($_("donor-deleted")); | ||||||
|     current_donors = current_donors.filter((d) => d.id !== event.detail.id); |     current_donors = current_donors.filter((d) => d.id !== event.detail.id); | ||||||
|     active_deletes = active_deletes.filter((a) => a.id !== event.detail.id); |     active_deletes = active_deletes.filter((a) => a.id !== event.detail.id); | ||||||
|     options.update((options) => ({ |     options.update((options) => ({ | ||||||
| @@ -203,7 +202,7 @@ | |||||||
|       bind:value={searchvalue} |       bind:value={searchvalue} | ||||||
|       placeholder={$_("datatable.search")} |       placeholder={$_("datatable.search")} | ||||||
|       aria-label={$_("datatable.search")} |       aria-label={$_("datatable.search")} | ||||||
|       class="mb-4" |       class="mb-2 w-full sm:w-auto mt-1 sm:mt-0 p-2 rounded-md border" | ||||||
|     /> |     /> | ||||||
|     <div |     <div | ||||||
|       class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll" |       class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll" | ||||||
|   | |||||||
| @@ -1,210 +1,196 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import { clickOutside } from "../base/outsideclick"; | 	import { clickOutside } from "../base/outsideclick"; | ||||||
|  |  | ||||||
|   export let modal_open; | 	let modal_open = false; | ||||||
|   (function () { | 	(function () { | ||||||
|     document.onkeydown = function (e) { | 		document.onkeydown = function (e) { | ||||||
|       e = e || window.event; | 			e = e || window.event; | ||||||
|       if (e.key === "Escape") { | 			if (e.key === "Escape") { | ||||||
|         modal_open = false; | 				modal_open = false; | ||||||
|       } | 			} | ||||||
|     }; | 		}; | ||||||
|   })(); | 	})(); | ||||||
|   const license_promise = fetch("/licenses.json"); | 	const license_promise = fetch("/licenses.json"); | ||||||
|   let licenses = []; | 	let licenses = []; | ||||||
|   $: currentlicense = ""; | 	$: currentlicense = ""; | ||||||
|   $: licensetext = ""; | 	$: licensetext = ""; | ||||||
|   license_promise | 	license_promise | ||||||
|     .then((response) => response.json()) | 		.then((response) => response.json()) | ||||||
|     .then((json) => { | 		.then((json) => { | ||||||
|       licenses = json; | 			licenses = json; | ||||||
|     }); | 		}); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div | 	<div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" | 		class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside | 		use:clickOutside | ||||||
|     on:click_outside={() => { | 		on:click_outside={() => { | ||||||
|       modal_open = false; | 			modal_open = false; | ||||||
|     }} | 		}} | ||||||
|   > | 	> | ||||||
|     <div | 		<div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" | 			class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 sm:block sm:p-0" | ||||||
|     > | 		> | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | 			<div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div | 				<div | ||||||
|           class="absolute inset-0 bg-gray-500 opacity-75" | 					class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|           data-id="modal_backdrop" | 					data-id="modal_backdrop" | ||||||
|         /> | 				/> | ||||||
|       </div> | 			</div> | ||||||
|       <span | 			<span | ||||||
|         class="hidden sm:inline-block sm:align-middle sm:h-screen" | 				class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|         aria-hidden="true">​</span | 				aria-hidden="true">​</span | ||||||
|       > | 			> | ||||||
|       <div | 			<div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" | 				class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" | 				role="dialog" | ||||||
|         aria-modal="true" | 				aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" | 				aria-labelledby="modal-headline" | ||||||
|       > | 			> | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> | 				<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> | 					<div class=""> | ||||||
|             <div | 						<div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | 							class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > | 						> | ||||||
|               <svg | 							<svg | ||||||
|                 fill="currentColor" | 								fill="currentColor" | ||||||
|                 class="h-6 w-6 text-blue-600" | 								class="h-6 w-6 text-blue-600" | ||||||
|                 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" | 								height="24" | ||||||
|                 ><path fill="none" d="M0 0h24v24H0z" /> | 								><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|                 <path | 								<path | ||||||
|                   d="M14 20v2H2v-2h12zM14.586.686l7.778 7.778L20.95 9.88l-1.06-.354L17.413 12l5.657 5.657-1.414 1.414L16 13.414l-2.404 2.404.283 1.132-1.415 1.414-7.778-7.778 1.415-1.414 1.13.282 6.294-6.293-.353-1.06L14.586.686z" | 									d="M14 20v2H2v-2h12zM14.586.686l7.778 7.778L20.95 9.88l-1.06-.354L17.413 12l5.657 5.657-1.414 1.414L16 13.414l-2.404 2.404.283 1.132-1.415 1.414-7.778-7.778 1.415-1.414 1.13.282 6.294-6.293-.353-1.06L14.586.686z" | ||||||
|                 /></svg | 								/></svg | ||||||
|               > | 							> | ||||||
|             </div> | 						</div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> | 						<div class="mt-3 sm:mt-0 sm:ml-4 sm:text-left"> | ||||||
|               <h3 class="text-lg leading-6 font-medium"> | 							<h3 class="text-lg leading-6 font-medium"> | ||||||
|                 {$_("read-license")} | 								{$_("read-license")} | ||||||
|               </h3> | 							</h3> | ||||||
|               <div class="mt-2 mb-6"> | 							<div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500">{currentlicense}</p> | 								<p class="text-sm text-gray-500">{currentlicense}</p> | ||||||
|               </div> | 							</div> | ||||||
|               <div class="mt-2 mb-6"> | 							<div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500">{licensetext}</p> | 								<p class="text-sm text-gray-500">{licensetext}</p> | ||||||
|               </div> | 							</div> | ||||||
|             </div> | 						</div> | ||||||
|           </div> | 					</div> | ||||||
|         </div> | 				</div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> | 				<div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button | 					<button | ||||||
|             on:click={() => { | 						on:click={() => { | ||||||
|               modal_open = false; | 							modal_open = false; | ||||||
|             }} | 						}} | ||||||
|             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:w-auto sm:text-sm" | ||||||
|           > | 					> | ||||||
|             {$_("close")} | 						{$_("close")} | ||||||
|           </button> | 					</button> | ||||||
|         </div> | 				</div> | ||||||
|       </div> | 			</div> | ||||||
|     </div> | 		</div> | ||||||
|   </div> | 	</div> | ||||||
| {/if} | {/if} | ||||||
| <!-- /// --> | <!-- /// --> | ||||||
| <div class="pt-12 px-4 sm:px-6 lg:px-8 lg:pt-20 bg-gray-900 pb-12"> | <section class="container p-5"> | ||||||
|   <div class="text-center mb-8"> | 	<h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     <h1 | 		{$_("about")} | ||||||
|       class="mt-9 font-display text-4xl leading-none font-semibold text-white sm:text-5xl lg:text-6xl" | 	</h4> | ||||||
|     > | 	<p class="mt-2 mb-2"> | ||||||
|       {$_("about")} | 		Lauf für Kaya! | ||||||
|       🧾 | 		<strong class="font-medium"> | ||||||
|     </h1> | 			{$_("by")} | ||||||
|     <p | 			<a href="https://odit.services" class="underline">ODIT.Services</a> | ||||||
|       class="mt-2 max-w-xl mx-auto text-xl lg:max-w-3xl lg:text-2xl text-gray-300" | 		</strong> | ||||||
|     > | 		<br /> | ||||||
|       Lauf für Kaya! | 		<span>{$_("lfk-is-os")}</span> | ||||||
|       <strong class="text-white font-medium"> | 	</p> | ||||||
|         {$_("by")} | 	<h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|         <a href="https://odit.services" class="underline">ODIT.Services</a> | 		{$_("credits")} | ||||||
|       </strong> | 	</h4> | ||||||
|       <br /> | 	<p class="text-left">{$_("oss_credit_description")}</p> | ||||||
|       <span class="text-lg">{$_("lfk-is-os")}</span> | 	<div class="mt-5 overflow-x-auto"> | ||||||
|     </p> | 		{#await license_promise} | ||||||
|   </div> | 			<p>{$_("licenses-are-being-loaded")}</p> | ||||||
| </div> | 		{:then} | ||||||
|  | 			<table class="font-mono"> | ||||||
| <div class="pt-0 pb-16 overflow-hidden lg:pt-12 lg:py-24"> | 				<thead class="border-b border-gray-400"> | ||||||
|   <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8"> | 					<tr class="odd:bg-white even:bg-gray-100"> | ||||||
|     <h2 class="text-4xl font-display font-semibold md:text-5xl"> | 						<th>{$_("dependency_name")}</th> | ||||||
|       {$_("credits")} | 						<th>{$_("license")}</th> | ||||||
|     </h2> | 						<th>{$_("repo_link")}</th> | ||||||
|     <div class="max-w-3xl mx-auto text-xl leading-8 font-medium mt-8"> | 						<th>{$_("installed-version")}</th> | ||||||
|       <p class="text-center">{$_("oss_credit_description")}</p> | 						<th>{$_("author")}</th> | ||||||
|     </div> | 					</tr> | ||||||
|     <div class="w-screen leading-8 pl-5 mt-5"> | 				</thead> | ||||||
|       {#await license_promise} | 				<tbody> | ||||||
|         <p class="text-center w-full">{$_("licenses-are-being-loaded")}</p> | 					{#each licenses as l} | ||||||
|       {:then} | 						<tr class="odd:bg-white even:bg-gray-100 *:p-2"> | ||||||
|         <table> | 							<td>{l.name}</td> | ||||||
|           <thead class="border-b border-gray-400"> | 							<td> | ||||||
|             <tr class="odd:bg-white even:bg-gray-100"> | 								<button | ||||||
|               <th>{$_("dependency_name")}</th> | 									class="underline cursor-pointer" | ||||||
|               <th>{$_("license")}</th> | 									on:click={() => { | ||||||
|               <th>{$_("repo_link")}</th> | 										modal_open = true; | ||||||
|               <th>{$_("installed-version")}</th> | 										currentlicense = l.name + "@" + l.version; | ||||||
|               <th>{$_("author")}</th> | 										licensetext = | ||||||
|             </tr> | 											l.licensetext || $_("no-license-text-could-be-found"); | ||||||
|           </thead> | 									}}>{l.license || "?"}</button | ||||||
|           <tbody> | 								> | ||||||
|             {#each licenses as l} | 							</td> | ||||||
|               <tr class="odd:bg-white even:bg-gray-100"> | 							<td> | ||||||
|                 <td>{l.name}</td> | 								{(l.repo?.url || l.repo) | ||||||
|                 <td> | 									.replace("git+", "") | ||||||
|                   {l.license || "?"}<br /><button | 									.replace("git://", "")} | ||||||
|                     class="underline cursor-pointer" | 							</td> | ||||||
|                     on:click={() => { | 							<td>{l.version || "?"}</td> | ||||||
|                       modal_open = true; | 							<td>{l.author?.name || l.author || "?"}</td> | ||||||
|                       currentlicense = l.name + "@" + l.version; | 						</tr> | ||||||
|                       licensetext = | 					{/each} | ||||||
|                         l.licensetext || $_("no-license-text-could-be-found"); | 				</tbody> | ||||||
|                     }}>{$_("read-license")}</button | 			</table> | ||||||
|                   > | 		{:catch error} | ||||||
|                 </td> | 			<div | ||||||
|                 <td> | 				class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500" | ||||||
|                   {(l.repo?.url || l.repo) | 			> | ||||||
|                     .replace("git+", "") | 				<span class="inline-block align-middle mr-8"> | ||||||
|                     .replace("git://", "")} | 					<b class="capitalize">{$_("general_promise_error")}</b> | ||||||
|                 </td> | 					{error} | ||||||
|                 <td>{l.version || "?"}</td> | 				</span> | ||||||
|                 <td>{l.author?.name || l.author || "?"}</td> | 			</div> | ||||||
|               </tr> | 		{/await} | ||||||
|             {/each} | 	</div> | ||||||
|           </tbody> | 	<div class="w-full mt-8"> | ||||||
|         </table> | 		<p class="font-medium">{$_("icon-image-credits")}</p> | ||||||
|       {:catch error} | 		<ul class="list-disc ml-6"> | ||||||
|         <div | 			<li> | ||||||
|           class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500" | 				<a | ||||||
|         > | 					class="underline" | ||||||
|           <span class="inline-block align-middle mr-8"> | 					target="_blank" | ||||||
|             <b class="capitalize">{$_("general_promise_error")}</b> | 					rel="noopener noreferrer" | ||||||
|             {error} | 					href="https://storyset.com">https://storyset.com</a | ||||||
|           </span> | 				> | ||||||
|         </div> | 			</li> | ||||||
|       {/await} | 			<li> | ||||||
|     </div> | 				<a | ||||||
|     <div class="w-full leading-8 mt-8"> | 					class="underline" | ||||||
|       <p class="text-xl font-medium">{$_("icon-image-credits")}</p> | 					target="_blank" | ||||||
|       <ul class="list-disc"> | 					rel="noopener noreferrer" | ||||||
|         <li> | 					href="https://undraw.co">https://undraw.co</a | ||||||
|           <a | 				> | ||||||
|             class="underline" | 			</li> | ||||||
|             target="_blank" | 			<li> | ||||||
|             rel="noopener noreferrer" | 				<a | ||||||
|             href="https://storyset.com">https://storyset.com</a | 					class="underline" | ||||||
|           > | 					target="_blank" | ||||||
|         </li> | 					rel="noopener noreferrer" | ||||||
|         <li> | 					href="https://remixicon.com">https://remixicon.com</a | ||||||
|           <a | 				> | ||||||
|             class="underline" | 			</li> | ||||||
|             target="_blank" | 		</ul> | ||||||
|             rel="noopener noreferrer" | 	</div> | ||||||
|             href="https://undraw.co">https://undraw.co</a | </section> | ||||||
|           > |  | ||||||
|         </li> |  | ||||||
|         <li> |  | ||||||
|           <a |  | ||||||
|             class="underline" |  | ||||||
|             target="_blank" |  | ||||||
|             rel="noopener noreferrer" |  | ||||||
|             href="https://remixicon.com">https://remixicon.com</a |  | ||||||
|           > |  | ||||||
|         </li> |  | ||||||
|       </ul> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </div> |  | ||||||
|   | |||||||
							
								
								
									
										496
									
								
								src/components/general/CardAssignment.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										496
									
								
								src/components/general/CardAssignment.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,496 @@ | |||||||
|  | <script> | ||||||
|  | 	import { _ } from "svelte-i18n"; | ||||||
|  | 	import { RunnerCardService, RunnerService } from "@odit/lfk-client-js"; | ||||||
|  | 	import QrCodeScanner from "./QrCodeScanner.svelte"; | ||||||
|  | 	let state = "scan_runner"; | ||||||
|  | 	let runnerinfo = { id: 0, firstname: "", lastname: "" }; | ||||||
|  | 	let cardCode = ""; | ||||||
|  | 	let scannerActive = true; | ||||||
|  | 	function resetAll() { | ||||||
|  | 		state = "scan_runner"; | ||||||
|  | 		runnerinfo = { id: 0, firstname: "", lastname: "" }; | ||||||
|  | 		cardCode = ""; | ||||||
|  | 		scannerActive = true; | ||||||
|  | 	} | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <div class="p-4"> | ||||||
|  | 	<h3 class="text-3xl font-bold">{$_("card_assignment_for_mobile")}</h3> | ||||||
|  | 	{#if state === "done"} | ||||||
|  | 		<div class="text-center mx-auto"> | ||||||
|  | 			<svg | ||||||
|  | 				class="h-64 mx-auto" | ||||||
|  | 				xmlns="http://www.w3.org/2000/svg" | ||||||
|  | 				viewBox="0 0 500 500" | ||||||
|  | 				><path | ||||||
|  | 					d="m339.91 38.77-2 1.14c-16.77 9.58-27.19 27.41-26.49 46.53a50.12 50.12 0 0 0 .81 7.33 54.34 54.34 0 0 0 32.62 39.6c9.79 3.94 21.14 5.27 28.8 12.46 10 9.36 9.88 24.8 9.1 38.36s-.83 29 9.18 38.32c6.27 5.84 15.36 7.88 24 7.65 22.8-.61 43.57-15.93 54.22-35.83s12.18-43.63 8.31-65.82c-5.46-31.09-21.78-60.95-47.75-79.33s-61.88-23.8-90.8-10.41ZM152.06 393l2.36-.64c19.89-5.4 35.44-21 39.85-41a55.18 55.18 0 0 0 1.13-7.79 58 58 0 0 0-23.09-49.67c-9.05-6.7-20.43-11.12-26.42-20.6-7.79-12.35-3.56-28.28.89-42.08s8.63-29.75.79-42.07c-4.91-7.71-13.75-12.25-22.71-14.32-23.71-5.49-49.29 4.77-65.63 22.48S34.94 239.14 33 263.11c-2.74 33.57 6.14 68.81 28.05 94.77s57.54 41.19 91.01 35.12Z" | ||||||
|  | 					style="fill:#f5f5f5" | ||||||
|  | 				/><circle | ||||||
|  | 					cx="409.16" | ||||||
|  | 					cy="320.55" | ||||||
|  | 					r="36.72" | ||||||
|  | 					style="fill:#f5f5f5" | ||||||
|  | 					transform="rotate(-45 409.165 320.548)" | ||||||
|  | 				/><path | ||||||
|  | 					d="M470.34 473.11c0 .15-98.66.26-220.33.26s-220.35-.11-220.35-.26 98.64-.26 220.35-.26 220.33.15 220.33.26Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M453.56 473.11a9.53 9.53 0 0 1-1-2c-.54-1.27-1.24-3-2-5s-1.4-3.53-2-5a14.87 14.87 0 0 1-.8-2.09 7.37 7.37 0 0 1 1.14 1.93c.61 1.25 1.36 3 2.13 5s1.42 3.75 1.87 5a10.55 10.55 0 0 1 .66 2.16ZM458.16 473.31c-.15 0-.66-3.33-1.59-7.41s-1.9-7.32-1.76-7.37a8.61 8.61 0 0 1 .84 2.07c.44 1.31 1 3.14 1.43 5.19s.77 3.93.94 5.29a8.54 8.54 0 0 1 .14 2.23ZM466.32 459.42c.14.08-1.36 3.08-2.88 6.91s-2.51 7-2.66 7a9.06 9.06 0 0 1 .46-2.15 53.35 53.35 0 0 1 3.93-9.86 8.66 8.66 0 0 1 1.15-1.9ZM225.88 473.11a74 74 0 0 1-6.08-10.68 71.59 71.59 0 0 1 6.08 10.68ZM230.2 473a79 79 0 0 1-2.66-12.67A82 82 0 0 1 230.2 473ZM239.31 461.69a39.45 39.45 0 0 1-3.08 5.76 41.06 41.06 0 0 1-3.53 5.49 39.66 39.66 0 0 1 3.08-5.75 42.46 42.46 0 0 1 3.53-5.5ZM55.68 473.11a29 29 0 0 1-2.94-4.68 29 29 0 0 1-2.49-4.93 29.84 29.84 0 0 1 2.94 4.68 29.92 29.92 0 0 1 2.49 4.93ZM58.09 457.6a60.92 60.92 0 0 1 1.17 7.73 56.51 56.51 0 0 1 .64 7.78 118.57 118.57 0 0 1-1.81-15.51ZM67.49 462.53a29.15 29.15 0 0 1-1.38 5.37 29.37 29.37 0 0 1-1.88 5.21 29.37 29.37 0 0 1 1.38-5.36 31.72 31.72 0 0 1 1.88-5.22Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M141.72 440a6.16 6.16 0 0 1 3.2 3.62 11 11 0 0 1 .43 4.91c-.37 3.19-2.18 6.4-4.12 8.95-2.69-2.34-3.3-6.43-3.49-8.52-.29-3.31 1.2-9.46 4-9M144.34 462.69a5.24 5.24 0 0 1 1.71-5 7 7 0 0 1 5.15-1.61 2.94 2.94 0 0 1 2.27 1 2.26 2.26 0 0 1 0 2.29 4.49 4.49 0 0 1-1.69 1.66c-2.32 1.46-4.84 2.44-7.47 1.65" | ||||||
|  | 					style="fill:#455a64" | ||||||
|  | 				/><path | ||||||
|  | 					d="M140.9 472.46a4.38 4.38 0 0 1 .1-.65c.08-.46.19-1.06.32-1.77a18.5 18.5 0 0 1 1.83-5.65 11.28 11.28 0 0 1 4.06-4.31 7.33 7.33 0 0 1 1.65-.73 3 3 0 0 1 .48-.12h.17a11.36 11.36 0 0 0-2.22 1 11.75 11.75 0 0 0-3.94 4.28 20.19 20.19 0 0 0-1.87 5.57c-.16.74-.29 1.34-.39 1.76a2.49 2.49 0 0 1-.19.62Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M141 444.74a1.36 1.36 0 0 1 0 .29l.05.82c0 .71.08 1.74.12 3 .08 2.55.14 6.08.13 10s-.11 7.42-.22 10c-.05 1.28-.1 2.31-.15 3 0 .33 0 .6-.05.82a1.33 1.33 0 0 1 0 .28 1.29 1.29 0 0 1 0-.29v-.82c0-.74.05-1.77.08-3 .06-2.55.13-6.08.15-10s0-7.42-.07-10V445c-.04-.16-.04-.26-.04-.26Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M139.7 464.63a12.32 12.32 0 0 0-6.72-9c-.9-.43-2.07-.71-2.81 0s-.57 1.86-.21 2.79a10.54 10.54 0 0 0 9.68 6.54" | ||||||
|  | 					style="fill:#455a64" | ||||||
|  | 				/><path | ||||||
|  | 					d="M133.41 458.63a3 3 0 0 1 .57.25 5.17 5.17 0 0 1 .64.34 9.69 9.69 0 0 1 .82.52 9.89 9.89 0 0 1 .94.7 11.62 11.62 0 0 1 1 .91 13.72 13.72 0 0 1 1.89 2.43 14 14 0 0 1 1.25 2.82 10.26 10.26 0 0 1 .31 1.31 9.15 9.15 0 0 1 .16 1.16 8.75 8.75 0 0 1 0 1v.73a4 4 0 0 1-.07.62s0-.89-.12-2.3a10.83 10.83 0 0 0-.19-1.14 11.51 11.51 0 0 0-.33-1.28 13.92 13.92 0 0 0-1.24-2.77 14.19 14.19 0 0 0-1.85-2.4 10.11 10.11 0 0 0-1-.91 10.49 10.49 0 0 0-.9-.72c-1.1-.9-1.9-1.22-1.88-1.27Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M411.83 430.38a8.16 8.16 0 0 1 4.22 4.79 14.35 14.35 0 0 1 .57 6.48c-.48 4.21-2.87 8.46-5.45 11.82-3.54-3.09-4.35-8.49-4.6-11.25-.38-4.36 1.58-12.49 5.26-11.84M415.29 460.41a7 7 0 0 1 2.25-6.61 9.26 9.26 0 0 1 6.81-2.13 3.89 3.89 0 0 1 3 1.35 3 3 0 0 1 .05 3 6 6 0 0 1-2.23 2.2c-3.07 1.93-6.4 3.23-9.87 2.18" | ||||||
|  | 					style="fill:#455a64" | ||||||
|  | 				/><path | ||||||
|  | 					d="M410.75 473.31a5.31 5.31 0 0 1 .13-.86l.42-2.34a24.66 24.66 0 0 1 2.42-7.46 14.9 14.9 0 0 1 5.35-5.69 10.1 10.1 0 0 1 2.19-1 6.47 6.47 0 0 1 .63-.16.61.61 0 0 1 .22 0 13.81 13.81 0 0 0-8.13 7 26.37 26.37 0 0 0-2.46 7.36c-.22 1-.39 1.77-.53 2.32a4.05 4.05 0 0 1-.24.83Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M410.88 436.7a1.65 1.65 0 0 1 .05.38q0 .42.06 1.08c.05.94.11 2.31.16 4 .11 3.38.19 8 .17 13.18s-.15 9.81-.28 13.18c-.07 1.69-.14 3.05-.2 4 0 .44 0 .8-.07 1.08a1.65 1.65 0 0 1 0 .38 2.21 2.21 0 0 1 0-.38v-1.08c0-1 .06-2.34.1-4 .08-3.37.17-8 .2-13.17s0-9.8-.09-13.17c0-1.66 0-3-.06-4v-1.09a2.79 2.79 0 0 1-.04-.39Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M409.16 463a16.22 16.22 0 0 0-8.88-11.92c-1.19-.57-2.73-.94-3.71-.06s-.75 2.46-.28 3.69a13.9 13.9 0 0 0 12.79 8.63" | ||||||
|  | 					style="fill:#455a64" | ||||||
|  | 				/><path | ||||||
|  | 					d="M400.85 455.05a3.47 3.47 0 0 1 .75.32 9.58 9.58 0 0 1 .85.46 10.94 10.94 0 0 1 1.08.68 12.91 12.91 0 0 1 1.24.93 15.58 15.58 0 0 1 1.32 1.19 16.82 16.82 0 0 1 4.15 6.94 16.17 16.17 0 0 1 .42 1.74 13.28 13.28 0 0 1 .21 1.53c.06.47 0 .9.06 1.28a9.24 9.24 0 0 1 0 1 4.38 4.38 0 0 1-.09.81c-.07 0 .05-1.17-.16-3-.06-.46-.12-1-.24-1.51s-.27-1.1-.44-1.69a18.46 18.46 0 0 0-1.64-3.65 19.56 19.56 0 0 0-2.44-3.18 17.44 17.44 0 0 0-1.28-1.2c-.41-.37-.83-.67-1.2-.95-1.55-1.16-2.62-1.64-2.59-1.7ZM155.45 292c0 .14-14 .26-31.2.26S93 292.15 93 292s14-.26 31.21-.26 31.24.12 31.24.26ZM136.75 284.1c0 .14-14 .26-31.2.26s-31.21-.12-31.21-.26 14-.26 31.21-.26 31.2.16 31.2.26ZM294.43 412.9c0 .14-8.07.26-18 .26s-18-.12-18-.26 8.06-.26 18-.26 18 .12 18 .26ZM283.64 405c0 .15-8.07.26-18 .26s-18-.11-18-.26 8.06-.26 18-.26 18 .11 18 .26Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><circle cx="88.02" cy="72.37" r="14.66" style="fill:#5e9cff" /><path | ||||||
|  | 					d="M88 87a14.68 14.68 0 0 1-13.52-9 14.78 14.78 0 0 1 0-11.43A14.84 14.84 0 0 1 77.64 62a14.69 14.69 0 0 1 20.76 0 14.84 14.84 0 0 1 3.14 4.66A14.67 14.67 0 0 1 88 87ZM85.93 105.14c-.08 0-.15-2.7-.15-6s.07-6 .15-6a56.83 56.83 0 0 1 .16 6 56.56 56.56 0 0 1-.16 6Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M85.93 105.16s-.08 0-.12-1.79v-8.55c0-1.78.09-1.78.12-1.78s.08 0 .13 1.78v8.55c-.06 1.79-.06 1.79-.13 1.79Zm0-12.08c-.07.22-.14 2.52-.14 6s.07 5.79.14 6c.07-.23.14-2.52.14-6s-.07-5.78-.14-6ZM77.48 89.64a63 63 0 0 1-3.07 5.64c-1.78 3.08-3.28 5.53-3.35 5.49a63.32 63.32 0 0 1 3.08-5.64c1.77-3.07 3.27-5.53 3.34-5.49Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M71.06 100.79s-.07 0 .84-1.7c.58-1.07 1.38-2.47 2.23-4s1.68-2.87 2.32-3.91c.89-1.46 1-1.58 1-1.58s.07 0-.84 1.7c-.58 1.07-1.37 2.48-2.23 4-1.52 2.64-3.22 5.46-3.35 5.5Zm6.41-11.12c-.18.17-1.46 2.25-3.32 5.47s-3 5.36-3.08 5.61c.18-.18 1.46-2.25 3.32-5.47s3.02-5.37 3.08-5.61ZM68.81 84.24a31 31 0 0 1-3.42 2.92 32.1 32.1 0 0 1-3.61 2.68 32.32 32.32 0 0 1 3.42-2.92 35.42 35.42 0 0 1 3.61-2.68Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M61.78 89.86s0-.06 1-.93c.65-.55 1.52-1.26 2.46-2a35.08 35.08 0 0 1 3.62-2.68 34.93 34.93 0 0 1-3.43 2.92c-.94.75-1.83 1.44-2.52 2a5 5 0 0 1-1.13.69Zm7-5.6a38.16 38.16 0 0 0-3.59 2.67 40.2 40.2 0 0 0-3.42 2.9 37.22 37.22 0 0 0 3.59-2.68 39.77 39.77 0 0 0 3.44-2.89Zm0 0ZM100.56 99.19a7.77 7.77 0 0 1-.39-1.49c-.21-.92-.51-2.19-.89-3.59s-.75-2.64-1-3.55a8.5 8.5 0 0 1-.41-1.48 7.14 7.14 0 0 1 .62 1.41c.33.89.75 2.14 1.12 3.54a36.32 36.32 0 0 1 .8 3.63 6.9 6.9 0 0 1 .15 1.53Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M100.55 99.2s-.11-.22-.4-1.5c-.19-.86-.5-2.16-.88-3.58s-.78-2.72-1-3.55c-.37-1.2-.45-1.46-.4-1.48s0 0 .22.37.27.64.42 1c.23.6.68 1.87 1.13 3.54s.69 3 .8 3.62a7.38 7.38 0 0 1 .17 1.54Zm-2.7-10.09a13.79 13.79 0 0 0 .41 1.43c.26.83.65 2.1 1 3.55s.69 2.73.88 3.59.32 1.37.37 1.46a10.18 10.18 0 0 0-.18-1.5c-.11-.64-.35-2-.8-3.62s-.9-2.94-1.13-3.54a9.12 9.12 0 0 0-.55-1.37ZM115.42 88.64a54.77 54.77 0 0 1-4.33-3.58 51.8 51.8 0 0 1-4.09-3.82 50.82 50.82 0 0 1 4.33 3.58 49.69 49.69 0 0 1 4.09 3.82Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M115.42 88.65a54.61 54.61 0 0 1-4.34-3.58c-1.13-1-2.18-1.93-3-2.65-1.22-1.13-1.19-1.17-1.17-1.19.15 0 2.34 1.85 4.33 3.59 1.13 1 2.19 1.93 3 2.65 1.22 1.13 1.18 1.17 1.16 1.19ZM107 81.26c.11.18 1.67 1.64 4.12 3.78s4.11 3.5 4.3 3.58c-.1-.19-1.67-1.64-4.12-3.79s-4.12-3.49-4.3-3.57ZM121.12 74.14a11.91 11.91 0 0 1-1.77-.26c-1.09-.18-2.59-.41-4.25-.6s-3.19-.3-4.29-.37a10.88 10.88 0 0 1-1.78-.16 8.74 8.74 0 0 1 1.79-.06 43.17 43.17 0 0 1 4.31.28c1.68.2 3.18.46 4.26.7a9.11 9.11 0 0 1 1.73.47Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M121.07 74.16c-.13 0-.49-.06-1.37-.2l-.35-.06c-1.49-.25-2.92-.45-4.26-.61s-2.77-.27-4.28-.37h-.35c-1.2-.08-1.44-.1-1.44-.15a9.68 9.68 0 0 1 1.79-.07 42.81 42.81 0 0 1 4.31.29 41.81 41.81 0 0 1 4.26.7 9.36 9.36 0 0 1 1.74.47s-.01 0-.05 0Zm-12-1.41a13.35 13.35 0 0 0 1.41.12h.35c1.51.1 3 .22 4.28.37s2.77.36 4.25.61l.35.06c.71.12 1.24.2 1.37.2a12.87 12.87 0 0 0-1.7-.44 41.81 41.81 0 0 0-4.26-.7 43 43 0 0 0-4.31-.29 13.47 13.47 0 0 0-1.75.07ZM121.14 59.88c0 .08-3.16.93-7.09 1.89s-7.14 1.66-7.16 1.58 3.15-.92 7.09-1.88 7.14-1.67 7.16-1.59Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M106.92 63.37s0-.08 2.07-.64c1.34-.35 3.13-.8 5-1.27s3.7-.88 5-1.18c2.11-.47 2.13-.42 2.13-.39s0 .07-2.07.63c-1.34.36-3.12.81-5 1.27s-3.69.88-5 1.18a16 16 0 0 1-2.13.4Zm14.18-3.48c-.29 0-3 .59-7.12 1.59s-6.8 1.73-7.06 1.86c.29 0 3-.58 7.13-1.59s6.8-1.75 7.05-1.86ZM104.57 43.27a63.61 63.61 0 0 1-3.39 5.41c-1.94 2.94-3.58 5.29-3.65 5.24s1.45-2.47 3.39-5.41 3.58-5.29 3.65-5.24Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M97.53 53.93c0-.14 1.72-2.9 3.39-5.42.94-1.42 1.84-2.75 2.53-3.74 1.06-1.52 1.12-1.52 1.14-1.5s.07 0-.93 1.64c-.65 1-1.52 2.37-2.46 3.79s-1.83 2.75-2.52 3.74c-.98 1.37-1.11 1.49-1.15 1.49Zm7-10.64c-.19.17-1.59 2.15-3.62 5.23s-3.32 5.14-3.39 5.37c.19-.16 1.58-2.14 3.62-5.22s3.34-5.14 3.42-5.38ZM88.13 39.8a12.88 12.88 0 0 1 0 2v4.85c0 1.85 0 3.61.06 4.85a14.66 14.66 0 0 1 0 2 11.36 11.36 0 0 1-.2-2c-.08-1.24-.14-3-.14-4.86s0-3.61.13-4.86a12.13 12.13 0 0 1 .15-1.98Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M88.15 53.54s-.05 0-.1-.55-.08-.88-.12-1.47c-.05-.84-.14-2.58-.14-4.86s.08-4 .13-4.86c0-.59.07-1.09.11-1.47s.08-.55.1-.55c.05 0 .07.19 0 2v4.85c0 1.91 0 3.54.05 4.77v2.08Zm0-13.71a18 18 0 0 0-.18 2c0 .83-.13 2.58-.13 4.85s.09 4 .14 4.86a16.64 16.64 0 0 0 .19 2v-2.08c0-1.23-.05-2.92-.05-4.77v-4.85c.03-.76.05-1.84.01-2.01ZM75.68 55.3c-.07.05-1.61-2.35-3.44-5.34s-3.24-5.47-3.19-5.51 1.62 2.35 3.45 5.35a63 63 0 0 1 3.18 5.5Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M75.68 55.32s-.16-.12-1.07-1.54c-.65-1-1.5-2.37-2.39-3.82-1.57-2.57-3.22-5.37-3.22-5.51s.07 0 1.09 1.54c.65 1 1.5 2.37 2.38 3.82s1.71 2.82 2.31 3.86c.94 1.63.9 1.65.87 1.67Zm-6.61-10.85c.06.24 1.26 2.34 3.18 5.48s3.24 5.16 3.42 5.33c-.07-.24-1.26-2.34-3.18-5.48s-3.24-5.16-3.42-5.33ZM68.25 61.62a7 7 0 0 1-1.56-.24c-1-.2-2.26-.52-3.69-.94s-2.7-.87-3.6-1.21a7.56 7.56 0 0 1-1.4-.64 8.28 8.28 0 0 1 1.52.43c.92.3 2.2.7 3.62 1.12s2.71.77 3.65 1a9.86 9.86 0 0 1 1.46.48Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M68.2 61.65h-.38c-.29 0-.68-.12-1.13-.22-.65-.13-2-.44-3.69-.94s-3-1-3.61-1.21l-1.07-.44c-.4-.17-.39-.2-.38-.22s.22 0 1.53.42c.74.24 2.12.68 3.62 1.13s2.6.74 3.65 1c1.34.36 1.53.43 1.52.48s0 0-.06 0ZM58 58.6a9.9 9.9 0 0 0 1.42.61c.62.24 1.9.71 3.61 1.21s3 .81 3.68.94a10.47 10.47 0 0 0 1.51.26 15.06 15.06 0 0 0-1.48-.44c-1-.28-2.29-.62-3.65-1s-2.89-.91-3.63-1.18c-.58-.15-1.36-.4-1.46-.4ZM65 72.89a38 38 0 0 1-4.68.6 37.31 37.31 0 0 1-4.71.3 35.07 35.07 0 0 1 4.68-.61 34.11 34.11 0 0 1 4.71-.29Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M55.88 73.83a1 1 0 0 1-.27 0 39.32 39.32 0 0 1 4.69-.6 39.75 39.75 0 0 1 4.72-.3 40.29 40.29 0 0 1-4.69.61c-1.81.14-3.74.29-4.45.29Zm-.24 0a43.5 43.5 0 0 0 4.68-.31 46 46 0 0 0 4.68-.63 43.61 43.61 0 0 0-4.69.31 39.33 39.33 0 0 0-4.67.59Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="m321.8 444.95 7.41 19.13 16.31-3.83 3.59-8.75-5.52-18.14-21.79 11.59z" | ||||||
|  | 					style="fill:#ffbf9d" | ||||||
|  | 				/><path | ||||||
|  | 					d="m349.94 449.25.58 1.45s29 0 31.09 4.61l-49.89 19.33-5.66-16.58c8.73.5 16.64-2.13 23.88-8.81Z" | ||||||
|  | 					style="fill:#455a64" | ||||||
|  | 				/><g style="opacity:.6000000000000001" | ||||||
|  | 					><path | ||||||
|  | 						d="M333.13 461.32a2.15 2.15 0 0 0-.52 2.83 2.11 2.11 0 0 0 2.84.5 2.25 2.25 0 0 0 .53-3 2.19 2.19 0 0 0-3-.2" | ||||||
|  | 						style="fill:#fff" | ||||||
|  | 					/></g | ||||||
|  | 				><g style="opacity:.6000000000000001" | ||||||
|  | 					><path | ||||||
|  | 						d="m331.72 474.64-1.36-4 48.32-17.07s2.59.09 2.93 1.73Z" | ||||||
|  | 						style="fill:#fff" | ||||||
|  | 					/></g | ||||||
|  | 				><path | ||||||
|  | 					d="M350.75 450.77c.08.24-1.1.82-2 2.06s-1.15 2.48-1.41 2.48-.44-1.54.68-3 2.69-1.78 2.73-1.54ZM356.81 450.87c.14.21-.76 1-1.19 2.36s-.26 2.5-.5 2.58-.93-1.21-.36-2.86 1.95-2.31 2.05-2.08ZM362.17 455.87c-.2.14-1-.93-.89-2.48s1.05-2.52 1.23-2.36-.25 1.14-.32 2.41.21 2.32-.02 2.43ZM259.73 325.23c.43 1.14 27.19 31 33.15 39.7 6.74 9.84 8.16 18.16 8.49 20.11 1.86 11.15 3.25 19 8.31 31.15S324.73 454 324.73 454l23.63-6.09s-13.93-59.44-15.19-69.34-3.38-17.57-8.87-26.67-29.71-58.77-29.71-58.77l-38.28 16.09Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M242.57 240.76s7.74.11 8.88.82 5.69 4.21 5.69 5a3 3 0 0 0 .32 1.38s2.86 4 1.57 5.71-2.24 2.27-2.21 2.8-.38 2.37-1.47 2.87a10.78 10.78 0 0 0-2.88 1.84 10.63 10.63 0 0 1-1.73 2.06 10.75 10.75 0 0 1-2.48 1.15 2.92 2.92 0 0 1-2.55 1.57c-1.64-.15-4.63-3.27-5.6-4.43-1.21-1.45-4.29-4-4.69-5.29a14.76 14.76 0 0 0-.92-2.3l-7.5-7.09 11.7-11.75Z" | ||||||
|  | 					style="fill:#ffbf9d" | ||||||
|  | 				/><path | ||||||
|  | 					d="M257.7 248.6a20.35 20.35 0 0 1-2.46-2.31 19.31 19.31 0 0 1-2.41-2.36 11.74 11.74 0 0 1 4.87 4.67Z" | ||||||
|  | 					style="fill:#ff9a6c" | ||||||
|  | 				/><path | ||||||
|  | 					d="M238.46 161.84s-8.9 7.54-11 9.43-29.46 24.87-31.29 35.27c-1.16 6.66 4 11.87 6.77 16.24 2 3.26 14.32 25.66 25.83 26.31.68 0 4.15 4.28 4.15 4.28l12.49-10.65a52.68 52.68 0 0 1-4.73-7c-5-9.38-15.89-24-15.55-24.66 2.43-4.55-3.34-3.47-3.34-3.47l23.94-21.95Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M198.89 199.64s-1.73-3.09 0-5.67S225 171.68 225 171.68s1.19.31 2.06 2.27-27 26.62-27 26.62Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M207.41 192.32s14 15.79 16 15.27 11.7-7.84 12.14-10.22-13.33-19-13.33-19ZM187.57 91.83c3.07.73 5.47 3.21 8.28 4.74 5.27 2.86 11.66 2.1 16.68-.23s9.1-6 13.61-9.1 8.09-6.22 14.6-6.81c11.49-1 23 9.11 17.78 17.7l-9.65 3.37a60.17 60.17 0 0 1-25.79 32.32c-2.42 1.47-5.16 2.83-8.17 2.45s-6.07-3.25-5.43-6c-4.78 1-9.7 1.92-14.7 1.17s-10.19-3.54-12.41-8-.26-10.48 4.56-11.35c-4.45-2.73-8.26-7.18-8.54-12s4.18-9.45 9.18-8.26Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M283.46 72.49c-6.22-1.69-12 .21-17.71 3.25a32.78 32.78 0 0 0-16.23 33.58 25.23 25.23 0 0 0 10.86 16.58c7.83 5 18.5 4.54 26.4-.31s13-13.65 14.27-22.84a30.7 30.7 0 0 0-3.05-18.6 23.36 23.36 0 0 0-14.53-11.66" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M263.37 92.26c1.16-2.33 1.06-5.07 1.68-7.6 1.36-5.57 3.94-10.5 9.42-12.19 5.1-1.57 13.45.3 19.16 2.78a22.62 22.62 0 0 1 9.88 7.9 17.84 17.84 0 0 1 1.71 16.26l-28.5-7c-2.92 2-5.92 4-9.32 4.91a6 6 0 0 1-3.07.19 2.7 2.7 0 0 1-2.06-2.07c-.16-1.15.59-2.17 1.1-3.18Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="m257.85 145 5-54.65a4.74 4.74 0 0 1 4.85-4.19l25.76-2.89c8.09.25 12 10.79 11.46 18.86-.65 9-1.81 19.89-3.77 26.38-3.94 13.05-14.39 13.35-14.39 13.35s-.06.52-.78 5.35c0 0-1.31 10-12.46 7.81-7.24-1.42-15.67-10.02-15.67-10.02Z" | ||||||
|  | 					style="fill:#ffbf9d" | ||||||
|  | 				/><path | ||||||
|  | 					d="M300.16 112.56a1.72 1.72 0 0 1-1.88 1.5 1.66 1.66 0 0 1-1.56-1.78 1.75 1.75 0 0 1 1.89-1.51 1.65 1.65 0 0 1 1.55 1.79ZM301.8 107.49c-.24.19-1.41-.94-3.25-1.19s-3.32.49-3.49.24.19-.49.84-.84a4.8 4.8 0 0 1 2.83-.46 4.49 4.49 0 0 1 2.54 1.22c.51.54.65.94.53 1.03ZM284.13 110.14a1.73 1.73 0 0 1-1.89 1.5 1.66 1.66 0 0 1-1.55-1.78 1.74 1.74 0 0 1 1.89-1.51 1.65 1.65 0 0 1 1.55 1.79ZM284.19 104.44c-.24.2-1.41-.94-3.25-1.19s-3.32.49-3.49.24.19-.49.84-.83a4.73 4.73 0 0 1 2.83-.47 4.49 4.49 0 0 1 2.54 1.23c.51.51.65.94.53 1.02ZM288.47 119.93a12.12 12.12 0 0 1 3.06-.14c.48 0 .94 0 1.06-.32a2.42 2.42 0 0 0-.12-1.44c-.29-1.2-.59-2.45-.9-3.77-1.24-5.36-2.06-9.74-1.84-9.79s1.39 4.26 2.62 9.62c.29 1.32.58 2.58.84 3.78a2.7 2.7 0 0 1 0 1.88 1.16 1.16 0 0 1-.86.58 3.79 3.79 0 0 1-.82 0 12.7 12.7 0 0 1-3.04-.4Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M286.76 141.88a34.19 34.19 0 0 1-17.21-7.2s3.23 9.85 16.75 10.42ZM287.09 124.26a3.35 3.35 0 0 0-2.81-1.64 3 3 0 0 0-2.24.83 1.93 1.93 0 0 0-.45 2.18 2.26 2.26 0 0 0 2.33.94 7.25 7.25 0 0 0 2.55-1.08 2.35 2.35 0 0 0 .6-.48.64.64 0 0 0 .09-.68" | ||||||
|  | 					style="fill:#ff9a6c" | ||||||
|  | 				/><path | ||||||
|  | 					d="M282.88 120.46c.3 0 0 2 1.55 3.67s3.67 1.73 3.65 2c0 .13-.53.32-1.43.22a5 5 0 0 1-3.06-1.56 4.31 4.31 0 0 1-1.17-3.06c.03-.84.32-1.3.46-1.27ZM285.77 97.11c-.25.47-2.06 0-4.25 0s-4 .31-4.25-.17c-.1-.24.27-.67 1-1a7.07 7.07 0 0 1 3.26-.67 7.2 7.2 0 0 1 3.21.83c.79.33 1.14.78 1.03 1.01ZM302.37 99.37c-.39.37-1.59-.24-3.12-.47s-2.85-.1-3.09-.58c-.1-.23.16-.62.78-.94a4.55 4.55 0 0 1 5 .84c.48.51.6.96.43 1.15Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M259.12 87.91c3.37-7.43 15.81-16.79 23.82-15.28l12 9.26a12.54 12.54 0 0 1-9.57 8.54c-2.36.42-5.13.29-6.72 2.09s-1.15 4.86-2.69 6.77c-2.12 2.66-7 1.95-8.69 4.89-.75 1.28-.63 2.94-1.4 4.21-1 1.69-5.82 3.43-7.62 2.61s-1.44-4-1.85-5.74a9 9 0 0 1 .42-6c1.26-3.65.7-7.8 2.3-11.35Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M263.59 113.23c.13-1-.7-3.49-1.66-3.78-2.56-.76-7.31-1.2-8.27 5.45-1.3 9.09 8.09 8.52 8.15 8.26s1.32-6.5 1.78-9.93Z" | ||||||
|  | 					style="fill:#ffbf9d" | ||||||
|  | 				/><path | ||||||
|  | 					d="M259.53 119.32s-.18.09-.46.17a1.64 1.64 0 0 1-1.19-.14c-.91-.49-1.5-2.13-1.31-3.78a5.29 5.29 0 0 1 .77-2.2 1.83 1.83 0 0 1 1.36-1 .82.82 0 0 1 .88.56c.08.28 0 .45 0 .47s.22-.12.2-.51a1 1 0 0 0-.28-.62 1.23 1.23 0 0 0-.84-.36 2.24 2.24 0 0 0-1.85 1.18 5.24 5.24 0 0 0-.91 2.45c-.21 1.84.48 3.69 1.74 4.25a1.68 1.68 0 0 0 1.48 0c.36-.25.43-.45.41-.47Z" | ||||||
|  | 					style="fill:#ff9a6c" | ||||||
|  | 				/><path | ||||||
|  | 					d="M292.56 78.87c.48 3.8 5.66 9.12 7.86 12.25 4.19 6 4.95 7.91 3.7 20.24 2.65-4 4.76-8 5.06-12.88a20 20 0 0 0-4-13.6 15.6 15.6 0 0 0-12.61-6" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M254.48 87.34a9.48 9.48 0 0 0 1.51.54c.49.16 1.1.34 1.82.5s1.52.39 2.44.52a43.13 43.13 0 0 0 6.47.7 49.17 49.17 0 0 0 7.95-.43 48.36 48.36 0 0 0 7.76-1.81 44.66 44.66 0 0 0 6-2.47c.85-.39 1.56-.83 2.2-1.19s1.18-.7 1.6-1a10.08 10.08 0 0 0 1.31-.94 9 9 0 0 0-1.42.76c-.44.26-1 .58-1.64.9s-1.37.75-2.21 1.11a49.36 49.36 0 0 1-6 2.34 52.85 52.85 0 0 1-7.69 1.75 53.22 53.22 0 0 1-7.86.47 47.11 47.11 0 0 1-6.42-.58c-.91-.11-1.72-.3-2.43-.44s-1.33-.28-1.83-.41a8.25 8.25 0 0 0-1.56-.32ZM252.89 93.79a3.74 3.74 0 0 0 1 .36 27.49 27.49 0 0 0 2.91.67 36.71 36.71 0 0 0 19.39-1.88 24.88 24.88 0 0 0 2.81-1.21 3.77 3.77 0 0 0 .94-.55c0-.08-1.44.59-3.8 1.4a41.36 41.36 0 0 1-19.2 1.85c-2.52-.34-4.03-.73-4.05-.64Z" | ||||||
|  | 					style="fill:#455a64" | ||||||
|  | 				/><path | ||||||
|  | 					d="m155.92 343.89-19.68-8-8.49 15.01 4.13 8.92 18.26 6.26 5.78-22.19z" | ||||||
|  | 					style="fill:#ffbf9d" | ||||||
|  | 				/><path | ||||||
|  | 					d="m133 362.05-1.5-.59s-20.27 21.82-25.21 20.16l20.18-51.36 16.53 7.53c-6.47 6.21-10 14.05-10 24.26Z" | ||||||
|  | 					style="fill:#455a64" | ||||||
|  | 				/><g style="opacity:.6000000000000001" | ||||||
|  | 					><path | ||||||
|  | 						d="M135.6 340.8a2.25 2.25 0 0 0-1.79-2.4 2.14 2.14 0 0 0-2.36 1.78 2.36 2.36 0 0 0 1.9 2.53 2.23 2.23 0 0 0 2.26-2.12" | ||||||
|  | 						style="fill:#fff" | ||||||
|  | 					/></g | ||||||
|  | 				><g style="opacity:.6000000000000001" | ||||||
|  | 					><path | ||||||
|  | 						d="m126.48 330.26 4 1.81-20.81 48.57s-1.87 1.89-3.35 1Z" | ||||||
|  | 						style="fill:#fff" | ||||||
|  | 					/></g | ||||||
|  | 				><path | ||||||
|  | 					d="M131.3 361.58c-.25-.11.13-1.41-.17-3s-1.09-2.64-.9-2.83 1.46.76 1.8 2.65-.53 3.33-.73 3.18ZM127 366.08c-.26 0-.26-1.3-1-2.57s-1.72-2-1.61-2.22 1.57.16 2.42 1.77.42 3.11.19 3.02ZM119.45 366.56c0-.25 1.4-.09 2.5 1.1s1.17 2.58.93 2.6-.69-1-1.6-2-1.91-1.44-1.83-1.7ZM145.78 339.09s15.36 4.19 25.9 6.15 22.64 4.78 31 7c8.81 2.29 12.72 3.59 12.72 3.59s2 2.61 3.5-7.74 6.1-47.73 6.1-47.73l5.06-16.08 30.38-5.32 16.12 21.27s-14.57 47.3-19.53 57.09-12 38.32-29.14 33.87c-10.14-2.63-89.33-27.5-89.33-27.5Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="m223.39 313.78-.13 1.06-.33 2.63 23.27-11.21s.15 10.69 22 19l2.78-4.84v-14.16l-16.89-13.13h-11.68l-18.61 14" | ||||||
|  | 					style="opacity:.30000000000000004" | ||||||
|  | 				/><path | ||||||
|  | 					d="M270.41 320.55a72.49 72.49 0 0 1-2.56 8.15 71.37 71.37 0 0 1-3.05 8 70.07 70.07 0 0 1 2.56-8.15 67 67 0 0 1 3.05-8ZM223.88 365.86a37.35 37.35 0 0 0-3.49-5.44 37.33 37.33 0 0 0-4.76-4.36 5.42 5.42 0 0 1 1.7.91 17 17 0 0 1 3.46 3.12 17.56 17.56 0 0 1 2.49 3.93 5.55 5.55 0 0 1 .6 1.84Z" | ||||||
|  | 					style="fill:#455a64" | ||||||
|  | 				/><path | ||||||
|  | 					d="M226.55 272.74s-5.06 13.2-4.88 20.65-2.73 22.38-2.73 22.38 27.33-14.67 29.37-16.45c0 0-2 14.72 21.22 21.58l2 .77 7.13-21.5a68.35 68.35 0 0 0 6.19-12c1.88-5.42 4.5-15.41 4.5-15.41L237.47 258Z" | ||||||
|  | 					style="fill:#455a64" | ||||||
|  | 				/><path | ||||||
|  | 					d="M289.38 287.64s12.76 17.61 12.94 20.49l-32.44 6.43-3-12.36-1.31-12.87Z" | ||||||
|  | 					style="fill:#455a64" | ||||||
|  | 				/><path | ||||||
|  | 					d="M239.86 171.23c.34.94 7 23.93 7 23.93l4 33.37s-6.73 19.75-12.4 26.21c-17.58 20.09-15.68 25.57-15.68 25.57s29.74-8 44.39-5.8 10.66 27.39 32 21.41l-.17-20.54s2.68-18.95 3.35-25.57-.24-30.41-.24-30.41 7.33-23.3 7.33-30.85 1.75-7.88-4.29-18.27-15-24.24-15-24.24l-33.63-2.84-18.64 19.21Z" | ||||||
|  | 					style="fill:#e0e0e0" | ||||||
|  | 				/><path | ||||||
|  | 					d="M281.7 292.51c.13 0-1.75 6.24-4.21 13.83s-4.56 13.72-4.7 13.67 1.75-6.23 4.21-13.83 4.56-13.72 4.7-13.67Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M238.71 172.17c-4.43 1.19-8.35 2.56-13.19 0s-8.89-7.36-9-12.84c-.06-4.48-.07-12.74 3.53-15.41s20.16-5.39 29.43-5.36c35.69.11 40.29 6 46 8.93a5.33 5.33 0 0 1-2.15 5.57" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M235.67 165.5s1 19.66 2.47 27.09 7.38 29.67 7.38 29.67-3.28 1.23-2.79 5.68c0 0-3.55 3.09-3.95 9.89s1.57 9.76 1.57 9.76l-3.84 7.72 64.36 12.17 1.08-7.27s4.66 3 5.51-11-.82-24.45-.08-37.3 5.53-17.86 4.3-29.47C311 175.62 289.35 147 289.35 147s-31.46-5.35-34.62-1.91-19.06 20.41-19.06 20.41Z" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M304 226.09c-15.48-8.7-26.72-23.17-37.53-37.27l-1.14-2.82c1.11 5.89 1.42 14.1 2.54 20a72.63 72.63 0 0 0 3.66 14.11 24.45 24.45 0 0 0 8.74 11.42c7 4.61 16.5 3.85 23.85-.1 1.08-.58 2.25-1.45 2.23-2.67s-1.28-2.05-2.35-2.67Z" | ||||||
|  | 					style="opacity:.30000000000000004" | ||||||
|  | 				/><path | ||||||
|  | 					d="M234.28 178.25a10.43 10.43 0 0 1 .6 1.69c.35 1.09.82 2.69 1.37 4.67 1.11 4 2.45 9.48 3.87 15.59s2.72 11.64 3.75 15.61c.51 1.93.93 3.51 1.24 4.71a11.9 11.9 0 0 1 .41 1.74 11.81 11.81 0 0 1-.6-1.69c-.37-1.09-.84-2.68-1.4-4.66-1.13-4-2.5-9.48-3.91-15.59s-2.7-11.64-3.71-15.62c-.5-1.92-.91-3.51-1.22-4.71a12.51 12.51 0 0 1-.4-1.74ZM265.5 233.75a26.55 26.55 0 0 1-3.27-1.23c-2-.79-4.76-1.89-7.89-2.86a49.52 49.52 0 0 0-8.18-1.79c-2.13-.26-3.46-.28-3.46-.37a2.82 2.82 0 0 1 .94-.08 20.82 20.82 0 0 1 2.56.09 39.56 39.56 0 0 1 8.29 1.66 69.24 69.24 0 0 1 7.89 3c1 .45 1.77.82 2.31 1.1a3.61 3.61 0 0 1 .81.48ZM305.27 259.42a4.28 4.28 0 0 1-.58.35 10.73 10.73 0 0 1-1.82.75 18.56 18.56 0 0 1-7.17.46 230.88 230.88 0 0 1-23.22-4.74c-9-2.19-17.11-4.25-23-5.61l-7-1.56-1.91-.42a3.36 3.36 0 0 1-.66-.18 3.14 3.14 0 0 1 .68.08l1.93.32c1.67.29 4.07.77 7 1.4 5.93 1.27 14.07 3.28 23.05 5.47s17.16 4 23.14 4.87a19.12 19.12 0 0 0 7.08-.29 23.9 23.9 0 0 0 2.48-.9Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M227.92 172.83c2.38 4 7.5 5.94 12.14 5.33s8.78-3.37 11.94-6.83 5.46-7.59 7.73-11.68l6.17-11.12c-7.32 3.05-9.81 11.52-15.35 17.2s-16.27 9.44-22.63 7.1" | ||||||
|  | 					style="opacity:.30000000000000004" | ||||||
|  | 				/><path | ||||||
|  | 					d="M266.52 148.59s-.73.18-2 .74a14.62 14.62 0 0 0-4.52 3.43 41.85 41.85 0 0 0-4.84 7 47 47 0 0 1-2.83 4.21 21.16 21.16 0 0 1-3.91 3.82 30.22 30.22 0 0 1-9.38 4.72 25 25 0 0 1-8.49 1.18 12.17 12.17 0 0 1-5.58-1.48 6.62 6.62 0 0 1-1.27-.93 2.54 2.54 0 0 1-.38-.4 18.82 18.82 0 0 0 1.75 1.16 12.65 12.65 0 0 0 5.5 1.28 25.19 25.19 0 0 0 8.33-1.27 30.59 30.59 0 0 0 9.21-4.67 21.42 21.42 0 0 0 3.82-3.72 47.6 47.6 0 0 0 2.82-4.15 40.4 40.4 0 0 1 5-7 14.13 14.13 0 0 1 4.7-3.36 9.15 9.15 0 0 1 1.5-.47 2 2 0 0 1 .57-.09ZM260.76 225.38c-.07.16-3.33-1.38-7.65-2.23a77 77 0 0 0-7.93-.88 8.27 8.27 0 0 1 2.35-.19 29.41 29.41 0 0 1 5.68.56 28.85 28.85 0 0 1 5.45 1.66 8.68 8.68 0 0 1 2.1 1.08ZM243 227.38c.07.07-.77 1-1.77 2.64a19.77 19.77 0 0 0-1.48 3.08 21.77 21.77 0 0 0-1 4.05 21.32 21.32 0 0 0-.16 4.17 20.22 20.22 0 0 0 .55 3.38c.48 1.89 1 3 .94 3a3.32 3.32 0 0 1-.44-.74 7.08 7.08 0 0 1-.41-.93 12.82 12.82 0 0 1-.45-1.26 17.38 17.38 0 0 1-.66-3.44 19.55 19.55 0 0 1 .11-4.29 20.16 20.16 0 0 1 1.1-4.14 17.53 17.53 0 0 1 1.62-3.11 12.25 12.25 0 0 1 .78-1.08 8.48 8.48 0 0 1 .66-.77c.38-.37.61-.58.61-.56Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M234.59 178.76a19.68 19.68 0 0 0 3.4 13.92c-.99-4.68-2.36-9.22-3.4-13.92Z" | ||||||
|  | 					style="opacity:.30000000000000004" | ||||||
|  | 				/><path | ||||||
|  | 					d="M340.48 208.44s5.27-6.17 6.6-6.62 7.22-1.77 7.88-1.22a3.09 3.09 0 0 0 1.33.67s5.11.33 5.66 2.55.34 3.33.78 3.66 1.67 1.89 1.33 3.11a11.48 11.48 0 0 0-.44 3.55 10.77 10.77 0 0 1 .5 2.78 11.39 11.39 0 0 1-.72 2.77 3.08 3.08 0 0 1-.45 3.11c-1.22 1.22-5.73 1.55-7.32 1.56-2 0-6.07.8-7.41.24a16.44 16.44 0 0 0-2.47-.8L335 225.08l-1.66-17.3Z" | ||||||
|  | 					style="fill:#ffbf9d" | ||||||
|  | 				/><path | ||||||
|  | 					d="M356.93 201.48a23.19 23.19 0 0 1-3.51.42 22.36 22.36 0 0 1-3.51.38 8.47 8.47 0 0 1 3.45-.9 8.38 8.38 0 0 1 3.57.1Z" | ||||||
|  | 					style="fill:#ff9a6c" | ||||||
|  | 				/><path | ||||||
|  | 					d="M264 182.13c4 10.83 7.79 25.38 10.6 33.79 3.81 11.43 15.63 15.68 21.67 16.14 7.73.58 45.4-6.55 45.4-6.55l-1.74-19-4.27.11a5.72 5.72 0 0 0-3-1.44c-7.93-1.87-29.3-.31-29.3-.31s-5.75-23.11-7-34.46c-1-9-1-23.68-15.07-24.53-9.15.43-15.06 3.81-17.29 13.61" | ||||||
|  | 					style="fill:#5e9cff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M264 159.53s0-.14.08-.4.16-.67.29-1.18a19.72 19.72 0 0 1 1.76-4.37 13.72 13.72 0 0 1 5.28-5.37 22.3 22.3 0 0 1 9.87-2.44l1.53.19a8.4 8.4 0 0 1 1.56.29l1.58.44 1.53.71a12.92 12.92 0 0 1 5 4.92 23.71 23.71 0 0 1 2.63 7.23 74 74 0 0 1 1.13 8.18 161.08 161.08 0 0 0 2.91 17.77c1.3 6.2 2.78 12.67 4.42 19.35l-.26-.18c5.12-.35 10.45-.59 15.92-.62 2.74 0 5.52 0 8.33.23a38.23 38.23 0 0 1 4.22.51 13.37 13.37 0 0 1 2.1.51 5.35 5.35 0 0 1 1.9 1.17l-.19-.07 4.27-.11h.24v.51c.59 6.41 1.17 12.7 1.72 18.7v.23h-.23c-7.65 1.43-15.09 2.73-22.26 3.88q-5.39.87-10.55 1.57c-3.45.47-6.82.88-10.14 1.06a22.36 22.36 0 0 1-9.5-1.65 28.77 28.77 0 0 1-7.87-4.54 23 23 0 0 1-5.39-6.5 36.76 36.76 0 0 1-2.74-7.26c-2.84-9.43-5-17-6.64-22.2-.82-2.6-1.49-4.59-1.95-5.94-.22-.66-.4-1.17-.52-1.53a5.06 5.06 0 0 1-.16-.52s.07.16.2.5.33.86.57 1.52c.49 1.34 1.19 3.32 2 5.91 1.72 5.16 3.91 12.75 6.79 22.16a36.86 36.86 0 0 0 2.75 7.18 22.52 22.52 0 0 0 5.32 6.37 28.72 28.72 0 0 0 7.76 4.45 22.15 22.15 0 0 0 9.33 1.59c3.29-.18 6.66-.6 10.1-1.07s6.95-1 10.53-1.59c7.16-1.16 14.6-2.46 22.24-3.89l-.21.27c-.55-6-1.13-12.28-1.72-18.69v-.26l.26.23-4.26.11h-.11l-.08-.08a6.64 6.64 0 0 0-3.74-1.54 36.32 36.32 0 0 0-4.16-.5c-2.78-.2-5.55-.24-8.28-.24-5.46 0-10.78.26-15.89.6h-.21l-.05-.21a536.51 536.51 0 0 1-4.39-19.37 156.74 156.74 0 0 1-2.88-17.83 74.73 74.73 0 0 0-1.1-8.14 23.43 23.43 0 0 0-2.55-7.13 12.64 12.64 0 0 0-4.89-4.8l-1.48-.7-1.54-.44a7.37 7.37 0 0 0-1.53-.29l-1.51-.2a22.13 22.13 0 0 0-9.77 2.35 13.6 13.6 0 0 0-5.25 5.24 20.45 20.45 0 0 0-1.82 4.31l-.33 1.17Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M298.27 216a19.44 19.44 0 0 0 5-11.61 5.13 5.13 0 0 1 .08 1.92 14.38 14.38 0 0 1-1.12 4.51 14.19 14.19 0 0 1-2.5 3.92 4.86 4.86 0 0 1-1.46 1.26ZM337 226a88.26 88.26 0 0 1-1.07-9.59 91.09 91.09 0 0 1-.54-9.64 87.31 87.31 0 0 1 1.06 9.6A89.66 89.66 0 0 1 337 226Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/></svg | ||||||
|  | 			> | ||||||
|  | 			<h3 class="text-2xl font-bold">{$_("done")}</h3> | ||||||
|  | 			<h4 class="text-xl font-semibold"> | ||||||
|  | 				{cardCode}<br />{runnerinfo.firstname} | ||||||
|  | 				{runnerinfo.lastname} [#{runnerinfo.id}] | ||||||
|  | 			</h4> | ||||||
|  | 			<button | ||||||
|  | 				on:click={() => { | ||||||
|  | 					resetAll(); | ||||||
|  | 				}} | ||||||
|  | 				type="button" | ||||||
|  | 				class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-100 text-blue-800 hover:bg-blue-200 focus:outline-hidden focus:bg-blue-200 disabled:opacity-50 disabled:pointer-events-none dark:text-blue-500 dark:bg-blue-800/30 dark:hover:bg-blue-800/20 dark:focus:bg-blue-800/20 mt-2" | ||||||
|  | 			> | ||||||
|  | 				{$_("next_runner")} | ||||||
|  | 			</button> | ||||||
|  | 		</div> | ||||||
|  | 	{:else if state === "assigning"} | ||||||
|  | 		<p class="text-center font-semibold"> | ||||||
|  | 			{$_("please_wait_a_moment_while_we_assign_the_card")}<br />{cardCode} | ||||||
|  | 		</p> | ||||||
|  | 	{:else if state === "error_runner"} | ||||||
|  | 		<div class="text-center mx-auto"> | ||||||
|  | 			<svg | ||||||
|  | 				class="h-64 mx-auto" | ||||||
|  | 				xmlns="http://www.w3.org/2000/svg" | ||||||
|  | 				viewBox="0 0 500 500" | ||||||
|  | 				><path | ||||||
|  | 					d="M298.37 335.5C382 299.85 469.46 233.1 432.31 135 398.6 46 284.74 25.75 219.62 102.47c-28.09 33.09-23.18 77.05-57.16 106.51s-90.4 45.83-75.13 104c23.67 89.93 156 46.02 211.04 22.52Z" | ||||||
|  | 					style="fill:#407bff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M298.37 335.5C382 299.85 469.46 233.1 432.31 135 398.6 46 284.74 25.75 219.62 102.47c-28.09 33.09-23.18 77.05-57.16 106.51s-90.4 45.83-75.13 104c23.67 89.93 156 46.02 211.04 22.52Z" | ||||||
|  | 					style="fill:#fff;opacity:.9" | ||||||
|  | 				/><path | ||||||
|  | 					d="M360.6 263.05h-.36c-26.64-2.18-45-25-45.74-25.92a4.47 4.47 0 0 1 7-5.55c.21.27 15.9 19.61 37.63 22.37 7-7 13-25.48 12.33-31.07v-.16c-.14-1.8-.48-8 1.29-11.65a4.47 4.47 0 0 1 8 3.88c-.44.92-.65 4.23-.44 7 1 9.2-7 32.42-17 40.19a4.47 4.47 0 0 1-2.71.91ZM148.82 238.82a65.8 65.8 0 0 1-48.56-22.28 4.46 4.46 0 0 1-.26-5.64c7.22-9.71 20-32.64 22-40.11a10.91 10.91 0 0 0-4.14-4.33 4.45 4.45 0 0 1-2.55-3.61l-.72-7.32a4.47 4.47 0 0 1 8.89-.88l.5 5.09a22.34 22.34 0 0 1 6.81 8.65 4.48 4.48 0 0 1 .32 2.26c-.92 7.93-13.79 30.9-21.71 42.51 18.49 18.43 40.59 16.75 41.56 16.66a4.47 4.47 0 0 1 .82 8.9c-.26.02-1.29.1-2.96.1ZM292.87 416.09h-12a4.47 4.47 0 0 1-4.31-5.66c3.13-11.24 4.67-20.39 5.82-34.71-4.24-20-8.23-38.21-8.27-38.39a4.47 4.47 0 0 1 8.73-1.91c0 .18 4.12 18.86 8.41 39.08a4.23 4.23 0 0 1 .08 1.28c-1 12.86-2.31 21.75-4.67 31.38h6.18a4.47 4.47 0 0 1 0 8.93ZM200.32 416.09h-6.76a4.45 4.45 0 0 1-4.42-5.08c1.15-8.2 7-23.13 13.3-38.14 2.23-19.8 4.05-36.8 4.07-37a4.47 4.47 0 1 1 8.88 1c0 .17-1.88 17.56-4.15 37.65a4.31 4.31 0 0 1-.32 1.22c-4.43 10.63-9.49 23.15-11.8 31.44h1.2a4.47 4.47 0 1 1 0 8.93Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="m204.21 111-52.06 52.07c-2.62 57.71-2.41 118.33 0 181.18h172.16c-3.41-81.1-3.73-159.17 0-233.25Z" | ||||||
|  | 					style="fill:#fff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M324.31 345.13H152.15a.9.9 0 0 1-.9-.86c-2.49-65.27-2.49-126.27 0-181.27a.9.9 0 0 1 .27-.59l52.06-52.07a.89.89 0 0 1 .63-.26h120.1a.9.9 0 0 1 .65.28.87.87 0 0 1 .24.66c-3.59 71.34-3.59 147.61 0 233.17a.89.89 0 0 1-.25.65.86.86 0 0 1-.64.29ZM153 343.34h170.38c-3.54-84.86-3.55-160.59 0-231.47h-118.8L153 163.43c-2.45 54.64-2.45 115.16 0 179.91Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M214.28 219.19c-.2-4.36-2.67-7.8-5.53-7.7s-5 3.71-4.82 8.07 2.67 7.8 5.53 7.69 5.02-3.71 4.82-8.06ZM274.65 217.82c-.2-4.35-2.67-7.79-5.53-7.69s-5 3.71-4.82 8.07 2.68 7.8 5.53 7.69 5.02-3.71 4.82-8.07ZM229.35 237a36.55 36.55 0 0 1 28.63 1.3 1.27 1.27 0 0 1 .49 1.74 1.3 1.3 0 0 1-1.75.49c-.15-.08-14.4-7.76-31.41 1a1.31 1.31 0 0 1-1.74-.54 1.27 1.27 0 0 1 .55-1.72 41.73 41.73 0 0 1 5.23-2.27ZM205.64 178.34a2.64 2.64 0 0 1 1.26.36 2.58 2.58 0 0 1 .92 3.51A25.29 25.29 0 0 1 188.27 195a2.59 2.59 0 0 1-2.69-2.45 2.55 2.55 0 0 1 2.44-2.66c.39 0 9.62-.58 15.36-10.27a2.52 2.52 0 0 1 2.26-1.28ZM266.05 176.87a2.57 2.57 0 0 1 2.33.72c8 8 17.14 6.39 17.52 6.32a2.6 2.6 0 0 1 3 2 2.54 2.54 0 0 1-2 3c-.5.09-12.14 2.31-22.21-7.75a2.54 2.54 0 0 1 1.31-4.3Z" | ||||||
|  | 					style="fill:#407bff" | ||||||
|  | 				/><path | ||||||
|  | 					d="m321.72 204.86-7.31.68a5.22 5.22 0 0 1-5.58-4.06L298.7 156.1a5.22 5.22 0 0 1 3.77-6.18l19.59-5.14ZM209 167.69c-5.09-13.89-10.18-36.12-4.81-56.71l-52.06 52.07c14.73 4.95 38.19 7.06 56.87 4.64Z" | ||||||
|  | 					style="opacity:.2" | ||||||
|  | 				/><path | ||||||
|  | 					d="M204.21 163.05c-5.71-16.86-3.38-39.78 0-52.07l-52.06 52.07c15.76 2.87 33.37 2.41 52.06 0Z" | ||||||
|  | 					style="fill:#fff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M176 165.92a133.14 133.14 0 0 1-24-2 .88.88 0 0 1-.47-1.5l52.06-52.07a.89.89 0 0 1 1.49.87c-3.14 11.44-5.75 34.6 0 51.54a.93.93 0 0 1-.09.76.87.87 0 0 1-.64.41 221.85 221.85 0 0 1-28.35 1.99Zm-22-3.46c13.84 2.29 29.91 2.24 49-.16-4.71-14.94-3.64-34.71-.48-48.4Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/></svg | ||||||
|  | 			> | ||||||
|  | 			<p class="text-lg font-semibold">{$_("runner_not_found")}</p> | ||||||
|  | 			<button | ||||||
|  | 				on:click={() => { | ||||||
|  | 					resetAll(); | ||||||
|  | 				}} | ||||||
|  | 				type="button" | ||||||
|  | 				class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-100 text-blue-800 hover:bg-blue-200 focus:outline-hidden focus:bg-blue-200 disabled:opacity-50 disabled:pointer-events-none dark:text-blue-500 dark:bg-blue-800/30 dark:hover:bg-blue-800/20 dark:focus:bg-blue-800/20 mt-2" | ||||||
|  | 			> | ||||||
|  | 				{$_("try_again")} | ||||||
|  | 			</button> | ||||||
|  | 		</div> | ||||||
|  | 	{:else if state === "error_card"} | ||||||
|  | 		<div class="text-center mx-auto"> | ||||||
|  | 			<svg | ||||||
|  | 				class="h-64 mx-auto" | ||||||
|  | 				xmlns="http://www.w3.org/2000/svg" | ||||||
|  | 				viewBox="0 0 500 500" | ||||||
|  | 				><path | ||||||
|  | 					d="M298.37 335.5C382 299.85 469.46 233.1 432.31 135 398.6 46 284.74 25.75 219.62 102.47c-28.09 33.09-23.18 77.05-57.16 106.51s-90.4 45.83-75.13 104c23.67 89.93 156 46.02 211.04 22.52Z" | ||||||
|  | 					style="fill:#407bff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M298.37 335.5C382 299.85 469.46 233.1 432.31 135 398.6 46 284.74 25.75 219.62 102.47c-28.09 33.09-23.18 77.05-57.16 106.51s-90.4 45.83-75.13 104c23.67 89.93 156 46.02 211.04 22.52Z" | ||||||
|  | 					style="fill:#fff;opacity:.9" | ||||||
|  | 				/><path | ||||||
|  | 					d="M360.6 263.05h-.36c-26.64-2.18-45-25-45.74-25.92a4.47 4.47 0 0 1 7-5.55c.21.27 15.9 19.61 37.63 22.37 7-7 13-25.48 12.33-31.07v-.16c-.14-1.8-.48-8 1.29-11.65a4.47 4.47 0 0 1 8 3.88c-.44.92-.65 4.23-.44 7 1 9.2-7 32.42-17 40.19a4.47 4.47 0 0 1-2.71.91ZM148.82 238.82a65.8 65.8 0 0 1-48.56-22.28 4.46 4.46 0 0 1-.26-5.64c7.22-9.71 20-32.64 22-40.11a10.91 10.91 0 0 0-4.14-4.33 4.45 4.45 0 0 1-2.55-3.61l-.72-7.32a4.47 4.47 0 0 1 8.89-.88l.5 5.09a22.34 22.34 0 0 1 6.81 8.65 4.48 4.48 0 0 1 .32 2.26c-.92 7.93-13.79 30.9-21.71 42.51 18.49 18.43 40.59 16.75 41.56 16.66a4.47 4.47 0 0 1 .82 8.9c-.26.02-1.29.1-2.96.1ZM292.87 416.09h-12a4.47 4.47 0 0 1-4.31-5.66c3.13-11.24 4.67-20.39 5.82-34.71-4.24-20-8.23-38.21-8.27-38.39a4.47 4.47 0 0 1 8.73-1.91c0 .18 4.12 18.86 8.41 39.08a4.23 4.23 0 0 1 .08 1.28c-1 12.86-2.31 21.75-4.67 31.38h6.18a4.47 4.47 0 0 1 0 8.93ZM200.32 416.09h-6.76a4.45 4.45 0 0 1-4.42-5.08c1.15-8.2 7-23.13 13.3-38.14 2.23-19.8 4.05-36.8 4.07-37a4.47 4.47 0 1 1 8.88 1c0 .17-1.88 17.56-4.15 37.65a4.31 4.31 0 0 1-.32 1.22c-4.43 10.63-9.49 23.15-11.8 31.44h1.2a4.47 4.47 0 1 1 0 8.93Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="m204.21 111-52.06 52.07c-2.62 57.71-2.41 118.33 0 181.18h172.16c-3.41-81.1-3.73-159.17 0-233.25Z" | ||||||
|  | 					style="fill:#fff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M324.31 345.13H152.15a.9.9 0 0 1-.9-.86c-2.49-65.27-2.49-126.27 0-181.27a.9.9 0 0 1 .27-.59l52.06-52.07a.89.89 0 0 1 .63-.26h120.1a.9.9 0 0 1 .65.28.87.87 0 0 1 .24.66c-3.59 71.34-3.59 147.61 0 233.17a.89.89 0 0 1-.25.65.86.86 0 0 1-.64.29ZM153 343.34h170.38c-3.54-84.86-3.55-160.59 0-231.47h-118.8L153 163.43c-2.45 54.64-2.45 115.16 0 179.91Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/><path | ||||||
|  | 					d="M214.28 219.19c-.2-4.36-2.67-7.8-5.53-7.7s-5 3.71-4.82 8.07 2.67 7.8 5.53 7.69 5.02-3.71 4.82-8.06ZM274.65 217.82c-.2-4.35-2.67-7.79-5.53-7.69s-5 3.71-4.82 8.07 2.68 7.8 5.53 7.69 5.02-3.71 4.82-8.07ZM229.35 237a36.55 36.55 0 0 1 28.63 1.3 1.27 1.27 0 0 1 .49 1.74 1.3 1.3 0 0 1-1.75.49c-.15-.08-14.4-7.76-31.41 1a1.31 1.31 0 0 1-1.74-.54 1.27 1.27 0 0 1 .55-1.72 41.73 41.73 0 0 1 5.23-2.27ZM205.64 178.34a2.64 2.64 0 0 1 1.26.36 2.58 2.58 0 0 1 .92 3.51A25.29 25.29 0 0 1 188.27 195a2.59 2.59 0 0 1-2.69-2.45 2.55 2.55 0 0 1 2.44-2.66c.39 0 9.62-.58 15.36-10.27a2.52 2.52 0 0 1 2.26-1.28ZM266.05 176.87a2.57 2.57 0 0 1 2.33.72c8 8 17.14 6.39 17.52 6.32a2.6 2.6 0 0 1 3 2 2.54 2.54 0 0 1-2 3c-.5.09-12.14 2.31-22.21-7.75a2.54 2.54 0 0 1 1.31-4.3Z" | ||||||
|  | 					style="fill:#407bff" | ||||||
|  | 				/><path | ||||||
|  | 					d="m321.72 204.86-7.31.68a5.22 5.22 0 0 1-5.58-4.06L298.7 156.1a5.22 5.22 0 0 1 3.77-6.18l19.59-5.14ZM209 167.69c-5.09-13.89-10.18-36.12-4.81-56.71l-52.06 52.07c14.73 4.95 38.19 7.06 56.87 4.64Z" | ||||||
|  | 					style="opacity:.2" | ||||||
|  | 				/><path | ||||||
|  | 					d="M204.21 163.05c-5.71-16.86-3.38-39.78 0-52.07l-52.06 52.07c15.76 2.87 33.37 2.41 52.06 0Z" | ||||||
|  | 					style="fill:#fff" | ||||||
|  | 				/><path | ||||||
|  | 					d="M176 165.92a133.14 133.14 0 0 1-24-2 .88.88 0 0 1-.47-1.5l52.06-52.07a.89.89 0 0 1 1.49.87c-3.14 11.44-5.75 34.6 0 51.54a.93.93 0 0 1-.09.76.87.87 0 0 1-.64.41 221.85 221.85 0 0 1-28.35 1.99Zm-22-3.46c13.84 2.29 29.91 2.24 49-.16-4.71-14.94-3.64-34.71-.48-48.4Z" | ||||||
|  | 					style="fill:#263238" | ||||||
|  | 				/></svg | ||||||
|  | 			> | ||||||
|  | 			<p class="text-lg font-semibold">{$_("card_not_found")}</p> | ||||||
|  | 			<button | ||||||
|  | 				on:click={() => { | ||||||
|  | 					state = "scan_card"; | ||||||
|  | 					scannerActive = true; | ||||||
|  | 				}} | ||||||
|  | 				type="button" | ||||||
|  | 				class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-100 text-blue-800 hover:bg-blue-200 focus:outline-hidden focus:bg-blue-200 disabled:opacity-50 disabled:pointer-events-none dark:text-blue-500 dark:bg-blue-800/30 dark:hover:bg-blue-800/20 dark:focus:bg-blue-800/20 mt-2" | ||||||
|  | 			> | ||||||
|  | 				{$_("try_again")} | ||||||
|  | 			</button> | ||||||
|  | 		</div> | ||||||
|  | 	{:else} | ||||||
|  | 		<!--  --> | ||||||
|  | 		{#if runnerinfo.id === 0} | ||||||
|  | 			<h3 class="text-2xl font-bold">{$_("scan_runner")}</h3> | ||||||
|  | 			<h4 class="text-xl font-semibold"> | ||||||
|  | 				{$_("selfservice_qr_registration_barcode")} | ||||||
|  | 			</h4> | ||||||
|  | 		{:else} | ||||||
|  | 			<h3 class="text-2xl font-bold"> | ||||||
|  | 				{runnerinfo.firstname} | ||||||
|  | 				{runnerinfo.lastname} | ||||||
|  | 			</h3> | ||||||
|  | 			<p> | ||||||
|  | 				ID: #{runnerinfo.id}<br />created_via: {runnerinfo.created_via}<br | ||||||
|  | 				/>{runnerinfo.group.name} | ||||||
|  | 			</p> | ||||||
|  | 		{/if} | ||||||
|  | 		<!--  --> | ||||||
|  | 	{/if} | ||||||
|  | 	{#if state === "scan_card"} | ||||||
|  | 		<h3 class="text-2xl font-bold">{$_("scan_card")}</h3> | ||||||
|  | 		<h4 class="text-xl font-semibold">{$_("code_128_barcode")}</h4> | ||||||
|  | 	{/if} | ||||||
|  | 	{#if state.includes("scan_")} | ||||||
|  | 		{#if scannerActive} | ||||||
|  | 			<QrCodeScanner | ||||||
|  | 				:paused={!scannerActive} | ||||||
|  | 				on:detect={(e) => { | ||||||
|  | 					if (scannerActive) { | ||||||
|  | 						scannerActive = false; | ||||||
|  | 						console.log({ type: "DETECT", code: e.detail.decodedText }); | ||||||
|  | 						if (runnerinfo.id === 0) { | ||||||
|  | 							new Audio("/beep.mp3").play(); | ||||||
|  | 							if ( | ||||||
|  | 								e.detail.decodedText.includes( | ||||||
|  | 									"https://portal.lauf-fuer-kaya.de/profile/" | ||||||
|  | 								) | ||||||
|  | 							) { | ||||||
|  | 								const runnerID = JSON.parse( | ||||||
|  | 									atob( | ||||||
|  | 										e.detail.decodedText | ||||||
|  | 											.replace("https://portal.lauf-fuer-kaya.de/profile/", "") | ||||||
|  | 											.split(".")[1] | ||||||
|  | 									) | ||||||
|  | 								).id; | ||||||
|  | 								RunnerService.runnerControllerGetOne(runnerID) | ||||||
|  | 									.then((runner) => { | ||||||
|  | 										runnerinfo = runner; | ||||||
|  | 									}) | ||||||
|  | 									.catch((e) => { | ||||||
|  | 										console.error(e); | ||||||
|  | 										state = "error_runner"; | ||||||
|  | 										// resetAll(); | ||||||
|  | 									}); | ||||||
|  | 							} else { | ||||||
|  | 								const runnerID = parseInt(e.detail.decodedText); | ||||||
|  | 								RunnerService.runnerControllerGetOne(runnerID) | ||||||
|  | 									.then((runner) => { | ||||||
|  | 										runnerinfo = runner; | ||||||
|  | 									}) | ||||||
|  | 									.catch((e) => { | ||||||
|  | 										console.error(e); | ||||||
|  | 										state = "error_runner"; | ||||||
|  | 										// resetAll(); | ||||||
|  | 									}); | ||||||
|  | 							} | ||||||
|  | 						} else { | ||||||
|  | 							if (`${e.detail.decodedText}`.length > 10) { | ||||||
|  | 								cardCode = e.detail.decodedText; | ||||||
|  | 								new Audio("/beep.mp3").play(); | ||||||
|  | 								state = "assigning"; | ||||||
|  | 								RunnerCardService.runnerCardControllerGetAll() | ||||||
|  | 									.then((cards) => { | ||||||
|  | 										console.log(cards); | ||||||
|  | 										const card = cards.find((c) => c.code === cardCode); | ||||||
|  | 										if (card) { | ||||||
|  | 											console.log("card found", card); | ||||||
|  | 											RunnerCardService.runnerCardControllerPut(card.id, { | ||||||
|  | 												enabled: true, | ||||||
|  | 												id: card.id, | ||||||
|  | 												runner: runnerinfo.id, | ||||||
|  | 											}) | ||||||
|  | 												.then(() => { | ||||||
|  | 													state = "done"; | ||||||
|  | 												}) | ||||||
|  | 												.catch(() => { | ||||||
|  | 													state = "error_card"; | ||||||
|  | 													scannerActive = false; | ||||||
|  | 												}); | ||||||
|  | 										} else { | ||||||
|  | 											scannerActive = true; | ||||||
|  | 										} | ||||||
|  | 									}) | ||||||
|  | 									.catch(() => { | ||||||
|  | 										scannerActive = true; | ||||||
|  | 									}); | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				}} | ||||||
|  | 				width={320} | ||||||
|  | 				height={320} | ||||||
|  | 				class="w-full max-w-sm bg-neutral-300 rounded-lg overflow-hidden" | ||||||
|  | 			/> | ||||||
|  | 		{/if} | ||||||
|  | 		{#if runnerinfo.id !== 0 && state !== "scan_card"} | ||||||
|  | 			<button | ||||||
|  | 				on:click={() => { | ||||||
|  | 					state = "scan_card"; | ||||||
|  | 					scannerActive = true; | ||||||
|  | 				}} | ||||||
|  | 				type="button" | ||||||
|  | 				class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-100 text-blue-800 hover:bg-blue-200 focus:outline-hidden focus:bg-blue-200 disabled:opacity-50 disabled:pointer-events-none dark:text-blue-500 dark:bg-blue-800/30 dark:hover:bg-blue-800/20 dark:focus:bg-blue-800/20 w-full mt-2" | ||||||
|  | 			> | ||||||
|  | 				{$_("scan_card")} | ||||||
|  | 			</button> | ||||||
|  | 		{/if} | ||||||
|  | 		{#if state === "scan_card" || runnerinfo.id !== 0} | ||||||
|  | 			<button | ||||||
|  | 				on:click={() => { | ||||||
|  | 					state = "scan_runner"; | ||||||
|  | 					scannerActive = true; | ||||||
|  | 					runnerinfo = { id: 0, firstname: "", lastname: "" }; | ||||||
|  | 					cardCode = ""; | ||||||
|  | 				}} | ||||||
|  | 				type="button" | ||||||
|  | 				class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-red-100 text-red-800 hover:bg-red-200 focus:outline-hidden focus:bg-red-200 disabled:opacity-50 disabled:pointer-events-none dark:text-red-500 dark:bg-red-800/30 dark:hover:bg-red-800/20 dark:focus:bg-red-800/20 w-full mt-2" | ||||||
|  | 			> | ||||||
|  | 				{$_("cancel")} | ||||||
|  | 			</button> | ||||||
|  | 		{/if} | ||||||
|  | 		<!--  --> | ||||||
|  | 	{/if} | ||||||
|  | </div> | ||||||
							
								
								
									
										91
									
								
								src/components/general/QrCodeScanner.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/components/general/QrCodeScanner.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | <script> | ||||||
|  | 	import { onMount, createEventDispatcher } from "svelte"; | ||||||
|  | 	import { | ||||||
|  | 		Html5QrcodeScanner, | ||||||
|  | 		Html5QrcodeScanType, | ||||||
|  | 		Html5QrcodeSupportedFormats, | ||||||
|  | 		Html5QrcodeScannerState, | ||||||
|  | 	} from "html5-qrcode"; | ||||||
|  |  | ||||||
|  | 	export let width; | ||||||
|  | 	export let height; | ||||||
|  | 	export let paused = false; | ||||||
|  |  | ||||||
|  | 	const dispatch = createEventDispatcher(); | ||||||
|  |  | ||||||
|  | 	const debounceFunc = (func, delay) => { | ||||||
|  | 		let timer; | ||||||
|  | 		return function (...args) { | ||||||
|  | 			const context = this; | ||||||
|  | 			clearTimeout(timer); | ||||||
|  | 			timer = setTimeout(() => { | ||||||
|  | 				func.apply(context, args); | ||||||
|  | 			}, delay); | ||||||
|  | 		}; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	const debouncedDispatch = debounceFunc(function (decodedText) { | ||||||
|  | 		console.log("dispatchEvent"); | ||||||
|  | 		dispatch("detect", { decodedText }); | ||||||
|  | 	}, 500); | ||||||
|  |  | ||||||
|  | 	function onScanSuccess(decodedText, decodedResult) { | ||||||
|  | 		if (!paused) { | ||||||
|  | 			debouncedDispatch(decodedText); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// usually better to ignore and keep scanning | ||||||
|  | 	function onScanFailure(message) { | ||||||
|  | 		if (!paused) { | ||||||
|  | 			dispatch("error", { message }); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	let scanner; | ||||||
|  | 	onMount(() => { | ||||||
|  | 		scanner = new Html5QrcodeScanner( | ||||||
|  | 			"qr-scanner", | ||||||
|  | 			{ | ||||||
|  | 				fps: 10, | ||||||
|  | 				showTorchButtonIfSupported: true, | ||||||
|  | 				rememberLastUsedCamera: true, | ||||||
|  | 				qrbox: { width, height }, | ||||||
|  | 				aspectRatio: 1, | ||||||
|  | 				supportedScanTypes: [Html5QrcodeScanType.SCAN_TYPE_CAMERA], | ||||||
|  | 				formatsToSupport: [ | ||||||
|  | 					Html5QrcodeSupportedFormats.CODE_39, | ||||||
|  | 					Html5QrcodeSupportedFormats.EAN_8, | ||||||
|  | 					Html5QrcodeSupportedFormats.EAN_13, | ||||||
|  | 					Html5QrcodeSupportedFormats.QR_CODE, | ||||||
|  | 					Html5QrcodeSupportedFormats.CODE_128, | ||||||
|  | 				], | ||||||
|  | 			}, | ||||||
|  | 			false // non-verbose | ||||||
|  | 		); | ||||||
|  | 		scanner.render(onScanSuccess, onScanFailure); | ||||||
|  | 	}); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <div id="qr-scanner" class={$$props.class} /> | ||||||
|  |  | ||||||
|  | <style> | ||||||
|  | 	/* Hide unwanted icons */ | ||||||
|  | 	#qr-scanner :global(img[alt="Info icon"]), | ||||||
|  | 	#qr-scanner :global(img[alt="Camera based scan"]) { | ||||||
|  | 		display: none; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Change camera permission button text */ | ||||||
|  | 	#qr-scanner :global(#html5-qrcode-button-camera-permission) { | ||||||
|  | 		visibility: hidden; | ||||||
|  | 	} | ||||||
|  | 	#qr-scanner :global(#html5-qrcode-button-camera-permission::after) { | ||||||
|  | 		position: absolute; | ||||||
|  | 		inset: auto 0 0; | ||||||
|  | 		display: block; | ||||||
|  | 		content: "Allow camera access"; | ||||||
|  | 		visibility: visible; | ||||||
|  | 		padding: 10px 0; | ||||||
|  | 	} | ||||||
|  | </style> | ||||||
| @@ -59,14 +59,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -79,15 +79,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 xmlns="http://www.w3.org/2000/svg" |                 xmlns="http://www.w3.org/2000/svg" | ||||||
| @@ -102,18 +102,18 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("create-a-new-user-group")} |                 {$_("create-a-new-user-group")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "please-provide-the-required-information-for-creating-a-new-user-group" |                     "please-provide-the-required-information-for-creating-a-new-user-group" | ||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="firstname" |                     for="firstname" | ||||||
| @@ -130,7 +130,7 @@ | |||||||
|                     bind:value={name_input_value} |                     bind:value={name_input_value} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="firstname" |                     name="firstname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isNameValid} |                   {#if !isNameValid} | ||||||
|                     <span |                     <span | ||||||
| @@ -152,20 +152,20 @@ | |||||||
|                     bind:value={description_input_value} |                     bind:value={description_input_value} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="trackname" |                     name="trackname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                 </div> |                 </div> | ||||||
|               </div> |               </div> | ||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("create")} |             {$_("create")} | ||||||
|           </button> |           </button> | ||||||
| @@ -174,7 +174,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -1,237 +1,227 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import store from "../../store"; | 	import store from "../../store"; | ||||||
|   import { UserGroupService } from "@odit/lfk-client-js"; | 	import { UserGroupService } from "@odit/lfk-client-js"; | ||||||
|  | 	import toast from "svelte-french-toast"; | ||||||
|  |  | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; | 	import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   let data_loaded = false; | 	let data_loaded = false; | ||||||
|   export let params; | 	export let params; | ||||||
|   const promise = UserGroupService.userGroupControllerGetOne(params.groupid); | 	const promise = UserGroupService.userGroupControllerGetOne(params.groupid); | ||||||
|   const colors = [ | 	const colors = [ | ||||||
|     "#f3558e", | 		"#f3558e", | ||||||
|     "#17b978", | 		"#17b978", | ||||||
|     "#3498db", | 		"#3498db", | ||||||
|     "#3f3b3b", | 		"#3f3b3b", | ||||||
|     "#775ada", | 		"#775ada", | ||||||
|     "#7ed6df_#000000", | 		"#7ed6df_#000000", | ||||||
|     "#000000", | 		"#000000", | ||||||
|     "#21e6c1_#000000", | 		"#21e6c1_#000000", | ||||||
|     "#c0392b", | 		"#c0392b", | ||||||
|     "#d35400", | 		"#d35400", | ||||||
|     "#7f8c8d", | 		"#7f8c8d", | ||||||
|     "#6ab04c", | 		"#6ab04c", | ||||||
|     "#4834d4", | 		"#4834d4", | ||||||
|     "#ff1f5a", | 		"#ff1f5a", | ||||||
|     "#eac100", | 		"#eac100", | ||||||
|   ]; | 	]; | ||||||
|   let matched_colors = []; | 	let matched_colors = []; | ||||||
|   $: delete_triggered = false; | 	$: delete_triggered = false; | ||||||
|   $: search_permission = ""; | 	$: search_permission = ""; | ||||||
|   $: original_data = {}; | 	$: original_data = {}; | ||||||
|   $: editable = {}; | 	$: editable = {}; | ||||||
|   $: changes_performed = !( | 	$: changes_performed = !( | ||||||
|     JSON.stringify(original_data) == JSON.stringify(editable) | 		JSON.stringify(original_data) == JSON.stringify(editable) | ||||||
|   ); | 	); | ||||||
|   $: isGroupnameValid = editable.name !== ""; | 	$: isGroupnameValid = editable.name !== ""; | ||||||
|   $: save_enabled = changes_performed && isGroupnameValid; | 	$: save_enabled = changes_performed && isGroupnameValid; | ||||||
|   promise.then((data) => { | 	promise.then((data) => { | ||||||
|     let current_target = ""; | 		let current_target = ""; | ||||||
|     let colorindex = -1; | 		let colorindex = -1; | ||||||
|     data.permissions = data.permissions.sort(); | 		data.permissions = data.permissions.sort(); | ||||||
|     data.permissions.forEach((p) => { | 		data.permissions.forEach((p) => { | ||||||
|       const target = p.split(":")[0]; | 			const target = p.split(":")[0]; | ||||||
|       if (current_target !== p.split(":")[0]) { | 			if (current_target !== p.split(":")[0]) { | ||||||
|         colorindex++; | 				colorindex++; | ||||||
|         current_target = p.split(":")[0]; | 				current_target = p.split(":")[0]; | ||||||
|       } | 			} | ||||||
|       let background = colors[colorindex]; | 			let background = colors[colorindex]; | ||||||
|       let foreground = "#fff"; | 			let foreground = "#fff"; | ||||||
|       if (background.includes("_")) { | 			if (background.includes("_")) { | ||||||
|         foreground = background.split("_")[1]; | 				foreground = background.split("_")[1]; | ||||||
|         background = background.split("_")[0]; | 				background = background.split("_")[0]; | ||||||
|       } | 			} | ||||||
|       matched_colors[target] = [background, foreground]; | 			matched_colors[target] = [background, foreground]; | ||||||
|     }); | 		}); | ||||||
|     data_loaded = true; | 		data_loaded = true; | ||||||
|     original_data = Object.assign(original_data, data); | 		original_data = Object.assign(original_data, data); | ||||||
|     editable = Object.assign(editable, original_data); | 		editable = Object.assign(editable, original_data); | ||||||
|   }); | 	}); | ||||||
|   function submit() { | 	function submit() { | ||||||
|     if (data_loaded === true && save_enabled) { | 		if (data_loaded === true && save_enabled) { | ||||||
|       toast($_("updating-group")); | 			toast($_("updating-group")); | ||||||
|       UserGroupService.userGroupControllerPut(original_data.id, editable) | 			UserGroupService.userGroupControllerPut(original_data.id, editable) | ||||||
|         .then((resp) => { | 				.then((resp) => { | ||||||
|           Object.assign(original_data, editable); | 					Object.assign(original_data, editable); | ||||||
|           original_data = editable; | 					original_data = editable; | ||||||
|           Object.assign(original_data, editable); | 					Object.assign(original_data, editable); | ||||||
|           toast.success($_("group-updated")); | 					toast.success($_("group-updated")); | ||||||
|         }) | 				}) | ||||||
|         .catch((err) => {}); | 				.catch((err) => {}); | ||||||
|     } else { | 		} else { | ||||||
|     } | 		} | ||||||
|   } | 	} | ||||||
|   function deleteGroup() { | 	function deleteGroup() { | ||||||
|     UserGroupService.userGroupControllerRemove(original_data.id, true) | 		UserGroupService.userGroupControllerRemove(original_data.id, true) | ||||||
|       .then((resp) => { | 			.then((resp) => { | ||||||
|         location.replace("./"); | 				location.replace("./"); | ||||||
|       }) | 			}) | ||||||
|       .catch((err) => {}); | 			.catch((err) => {}); | ||||||
|   } | 	} | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#await promise} | {#await promise} | ||||||
|   {$_("loading-group-detail")} | 	{$_("loading-group-detail")} | ||||||
| {:then} | {:then} | ||||||
|   <section class="container p-5 select-none"> | 	<section class="container p-5 select-none"> | ||||||
|     <div class="flex flex-row mb-4"> | 		<div class="flex flex-row mb-4"> | ||||||
|       <div class="w-full"> | 			<div class="w-full"> | ||||||
|         <nav class="w-full flex"> | 				<nav class="w-full flex"> | ||||||
|           <ol class="list-none flex flex-row items-center justify-start"> | 					<ol class="list-none flex flex-row items-center justify-start"> | ||||||
|             <li class="flex items-center"> | 						<li class="flex items-center"></li> | ||||||
|               <svg | 						<li class="flex items-center"> | ||||||
|                 class="flex-shrink-0 w-5 h-5 mr-2" | 							<a class="mr-2" href="../" | ||||||
|                 fill="currentColor" | 								><svg | ||||||
|                 width="24" | 									xmlns="http://www.w3.org/2000/svg" | ||||||
|                 height="24" | 									width="24" | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 									height="24" | ||||||
|                 viewBox="0 0 640 512" | 									viewBox="0 0 24 24" | ||||||
|                 ><path | 									fill="none" | ||||||
|                   fill="currentColor" | 									stroke="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" | 									stroke-width="2" | ||||||
|                 /></svg | 									stroke-linecap="round" | ||||||
|               > | 									stroke-linejoin="round" | ||||||
|             </li> | 									class="inline-block" | ||||||
|             <li class="flex items-center"> | 									><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg | ||||||
|               <a class="mr-2" href="../">{$_("groups")}</a><svg | 								> | ||||||
|                 stroke="currentColor" | 								{$_("groups")}</a | ||||||
|                 fill="none" | 							> | ||||||
|                 stroke-width="2" | 						</li> | ||||||
|                 viewBox="0 0 24 24" | 					</ol> | ||||||
|                 stroke-linecap="round" | 				</nav> | ||||||
|                 stroke-linejoin="round" | 			</div> | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" | 		</div> | ||||||
|                 height="1em" | 		<div class="mb-4 text-3xl font-extrabold leading-tight"> | ||||||
|                 width="1em" | 			{editable.name} | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 			<div data-id="group_actions_${editable.id}"> | ||||||
|                 ><line x1="5" y1="12" x2="19" y2="12" /> | 				{#if store.state.jwtinfo.userdetails.permissions.includes("USERGROUP:DELETE")} | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg | 					{#if delete_triggered} | ||||||
|               > | 						<button | ||||||
|             </li> | 							on:click={deleteGroup} | ||||||
|             <li class="flex items-center"> | 							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:w-auto sm:text-sm" | ||||||
|               <span class="mr-2">{editable.name}</span> | 							>{$_("confirm-deletion")}</button | ||||||
|             </li> | 						> | ||||||
|           </ol> | 						<button | ||||||
|         </nav> | 							on:click={() => { | ||||||
|       </div> | 								delete_triggered = !delete_triggered; | ||||||
|     </div> | 							}} | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> | 							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" | ||||||
|       {original_data.name} | 							>{$_("cancel")}</button | ||||||
|       <span data-id="group_actions_${editable.id}"> | 						> | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("USERGROUP:DELETE")} | 					{/if} | ||||||
|           {#if delete_triggered} | 					{#if !delete_triggered} | ||||||
|             <button | 						<button | ||||||
|               on:click={deleteGroup} | 							on:click={() => { | ||||||
|               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_triggered = true; | ||||||
|               >{$_("confirm-deletion")}</button | 							}} | ||||||
|             > | 							type="button" | ||||||
|             <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:w-auto sm:text-sm" | ||||||
|               on:click={() => { | 							>{$_("delete-group")}</button | ||||||
|                 delete_triggered = !delete_triggered; | 						> | ||||||
|               }} | 					{/if} | ||||||
|               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" | 				{/if} | ||||||
|               >{$_("cancel")}</button | 				{#if !delete_triggered} | ||||||
|             > | 					<button | ||||||
|           {/if} | 						disabled={!save_enabled} | ||||||
|           {#if !delete_triggered} | 						class:opacity-50={!save_enabled} | ||||||
|             <button | 						type="button" | ||||||
|               on:click={() => { | 						on:click={submit} | ||||||
|                 delete_triggered = true; | 						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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|               }} | 						>{$_("save-changes")}</button | ||||||
|               type="button" | 					> | ||||||
|               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm" | 				{/if} | ||||||
|               >{$_("delete-group")}</button | 			</div> | ||||||
|             > | 		</div> | ||||||
|           {/if} | 		<!--  --> | ||||||
|         {/if} | 		<div class="text-sm w-full mt-2"> | ||||||
|         {#if !delete_triggered} | 			<label for="title" class="font-semibold text-gray-700">{$_("name")}</label | ||||||
|           <button | 			> | ||||||
|             disabled={!save_enabled} | 			<input | ||||||
|             class:opacity-50={!save_enabled} | 				autocomplete="off" | ||||||
|             type="button" | 				placeholder={$_("name")} | ||||||
|             on:click={submit} | 				type="text" | ||||||
|             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" | 				bind:value={editable.name} | ||||||
|             >{$_("save-changes")}</button | 				class:border-red-500={!isGroupnameValid} | ||||||
|           > | 				class:focus:border-red-500={!isGroupnameValid} | ||||||
|         {/if} | 				class:focus:ring-red-500={!isGroupnameValid} | ||||||
|       </span> | 				name="title" | ||||||
|     </div> | 				class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|     <!--  --> | 			/> | ||||||
|     <div class="text-sm w-full"> | 			{#if !isGroupnameValid} | ||||||
|       <label for="title" class="font-medium text-gray-700">{$_("name")}</label> | 				<span | ||||||
|       <input | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|         autocomplete="off" | 				> | ||||||
|         placeholder={$_("name")} | 					{$_("group-name-is-required")} | ||||||
|         type="text" | 				</span> | ||||||
|         bind:value={editable.name} | 			{/if} | ||||||
|         class:border-red-500={!isGroupnameValid} | 		</div> | ||||||
|         class:focus:border-red-500={!isGroupnameValid} | 		<div class="text-sm w-full mt-2"> | ||||||
|         class:focus:ring-red-500={!isGroupnameValid} | 			<label for="groupdescription" class="font-semibold text-gray-700" | ||||||
|         name="title" | 				>{$_("description")}</label | ||||||
|         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" | 			> | ||||||
|       /> | 			<input | ||||||
|       {#if !isGroupnameValid} | 				autocomplete="off" | ||||||
|         <span | 				placeholder={$_("description")} | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 				type="text" | ||||||
|         > | 				bind:value={editable.description} | ||||||
|           {$_("group-name-is-required")} | 				name="groupdescription" | ||||||
|         </span> | 				class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|       {/if} | 			/> | ||||||
|     </div> | 		</div> | ||||||
|     <div class="text-sm w-full"> | 		<div class="text-sm w-full mt-2"> | ||||||
|       <label for="firstname" class="font-medium text-gray-700" | 			<p class="font-semibold mb-4"> | ||||||
|         >{$_("description")}</label | 				{$_("permissions")} | ||||||
|       > | 			</p> | ||||||
|       <input | 			<div> | ||||||
|         autocomplete="off" | 				<a | ||||||
|         placeholder={$_("description")} | 					class="px-4 py-2 bg-gray-500 rounded-md text-white" | ||||||
|         type="text" | 					href="/groups/{params.groupid}/permissions/" | ||||||
|         bind:value={editable.description} | 					>{$_("edit-permissions")}</a | ||||||
|         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" | 			</div> | ||||||
|       /> | 			<div class="w-full sm:my-px sm:px-px sm:w-1/2"> | ||||||
|     </div> | 				<input | ||||||
|     <div class="text-sm w-full mt-8"> | 					autocomplete="off" | ||||||
|       <p class="font-medium mb-4"> | 					placeholder={$_("search-for-permission")} | ||||||
|         {$_("permissions")} | 					type="text" | ||||||
|         <a | 					bind:value={search_permission} | ||||||
|           class="px-4 py-2 bg-gray-500 rounded-md text-white" | 					class="mt-4 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|           href="/groups/{params.groupid}/permissions/" | 				/> | ||||||
|           >{$_("edit-permissions")}</a | 			</div> | ||||||
|         > | 			{#each original_data.permissions as p} | ||||||
|       </p> | 				{#if p.toLowerCase().includes(search_permission.toLowerCase())} | ||||||
|       <div class="w-full sm:my-px sm:px-px sm:w-1/2"> | 					<span | ||||||
|         <input | 						style="background:{matched_colors[ | ||||||
|           autocomplete="off" | 							p.split(':')[0] | ||||||
|           placeholder={$_("search-for-permission")} | 						][0]};color:{matched_colors[p.split(':')[0]][1]};" | ||||||
|           type="text" | 						class="mt-1 inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none text-indigo-100 rounded" | ||||||
|           bind:value={search_permission} | 						>{p}</span | ||||||
|           class="mt-4 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> | 				{/if} | ||||||
|       {#each original_data.permissions as p} | 			{/each} | ||||||
|         {#if p.toLowerCase().includes(search_permission.toLowerCase())} | 		</div> | ||||||
|           <span | 	</section> | ||||||
|             style="background:{matched_colors[ |  | ||||||
|               p.split(':')[0] |  | ||||||
|             ][0]};color:{matched_colors[p.split(':')[0]][1]};" |  | ||||||
|             class="mt-1 inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none text-indigo-100 rounded" |  | ||||||
|             >{p}</span |  | ||||||
|           > |  | ||||||
|           <!--  --> |  | ||||||
|         {/if} |  | ||||||
|       {/each} |  | ||||||
|     </div> |  | ||||||
|   </section> |  | ||||||
| {:catch error} | {:catch error} | ||||||
|   <PromiseError {error} /> | 	<PromiseError {error} /> | ||||||
| {/await} | {/await} | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
|     CreatePermission, |     CreatePermission, | ||||||
|     UserGroupService, |     UserGroupService, | ||||||
|   } from "@odit/lfk-client-js"; |   } from "@odit/lfk-client-js"; | ||||||
|  |   import toast from 'svelte-french-toast' | ||||||
|  |  | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; |   import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   export let params; |   export let params; | ||||||
| @@ -49,7 +50,7 @@ | |||||||
|         ); |         ); | ||||||
|       }); |       }); | ||||||
|       grantedPermissions_initial = grantedPermissions; |       grantedPermissions_initial = grantedPermissions; | ||||||
|       toast($_("permissions-updated")); |       toast.success($_("permissions-updated")); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|   Object.values(CreatePermission.target).forEach((t) => { |   Object.values(CreatePermission.target).forEach((t) => { | ||||||
| @@ -132,27 +133,25 @@ | |||||||
|         </nav> |         </nav> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|     <div class="mb-8 text-3xl font-extrabold"> |     <div class="mb-4 text-3xl font-extrabold"> | ||||||
|       {$_("permissions")}: |       <div> | ||||||
|       {original_data.name} |  | ||||||
|       <span> |  | ||||||
|         {#if promises.length === 0} |         {#if promises.length === 0} | ||||||
|           <button |           <button | ||||||
|             disabled={save_enabled} |             disabled={save_enabled} | ||||||
|             class:opacity-50={save_enabled} |             class:opacity-50={save_enabled} | ||||||
|             type="button" |             type="button" | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             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" |             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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|             >{$_("save-changes")}</button |             >{$_("save-changes")}</button | ||||||
|           > |           > | ||||||
|         {:else} |         {:else} | ||||||
|           <button |           <button | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-yellow-600 text-base font-medium text-white hover:bg-yellow-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-yellow-600 text-base font-medium text-white hover:bg-yellow-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500 sm:w-auto sm:text-sm" | ||||||
|             >{$_("applying-changes")}</button |             >{$_("applying-changes")}</button | ||||||
|           > |           > | ||||||
|         {/if} |         {/if} | ||||||
|       </span> |       </div> | ||||||
|     </div> |     </div> | ||||||
|     <!--  --> |     <!--  --> | ||||||
|     <div class="flex flex-wrap -mx-1 overflow-hidden"> |     <div class="flex flex-wrap -mx-1 overflow-hidden"> | ||||||
| @@ -192,7 +191,7 @@ | |||||||
|                       } |                       } | ||||||
|                     }} |                     }} | ||||||
|                     type="button" |                     type="button" | ||||||
|                     class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-green-200 text-base font-medium text-black hover:bg-green-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 sm:ml-3 sm:w-auto sm:text-sm" |                     class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-green-200 text-base font-medium text-black hover:bg-green-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500 sm:w-auto sm:text-sm" | ||||||
|                     >+</button |                     >+</button | ||||||
|                   > |                   > | ||||||
|                 </p> |                 </p> | ||||||
| @@ -232,7 +231,7 @@ | |||||||
|                     } |                     } | ||||||
|                   }} |                   }} | ||||||
|                   type="button" |                   type="button" | ||||||
|                   class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-300 text-base font-medium text-black hover:bg-red-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 sm:ml-3 sm:w-auto sm:text-sm" |                   class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-300 text-base font-medium text-black hover:bg-red-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 sm:w-auto sm:text-sm" | ||||||
|                   >-</button |                   >-</button | ||||||
|                 > |                 > | ||||||
|               </p> |               </p> | ||||||
|   | |||||||
| @@ -8,20 +8,20 @@ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> |   <h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_("user-groups")} |     {$_("user-groups")} | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("USERGROUP:CREATE")} |   </h4> | ||||||
|       <button |   {#if store.state.jwtinfo.userdetails.permissions.includes("USERGROUP:CREATE")} | ||||||
|         on:click={() => { |     <button | ||||||
|           modal_open = true; |       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" |       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:w-auto sm:text-sm" | ||||||
|         {$_("add-user-group")} |     > | ||||||
|       </button> |       {$_("add-user-group")} | ||||||
|     {/if} |     </button> | ||||||
|   </span> |   {/if} | ||||||
|   <UserGroupsOverview bind:current_groups /> |   <UserGroupsOverview bind:current_groups /> | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -31,7 +31,7 @@ | |||||||
|         bind:value={searchvalue} |         bind:value={searchvalue} | ||||||
|         placeholder={$_("datatable.search")} |         placeholder={$_("datatable.search")} | ||||||
|         aria-label={$_("datatable.search")} |         aria-label={$_("datatable.search")} | ||||||
|         class="mb-4" |         class="mb-2 w-full sm:w-auto mt-1 sm:mt-0 p-2 rounded-md border" | ||||||
|       /> |       /> | ||||||
|       <div |       <div | ||||||
|         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll" |         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll" | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ | |||||||
|   $: address_input2_value = ""; |   $: address_input2_value = ""; | ||||||
|   $: address_zipcode_value = ""; |   $: address_zipcode_value = ""; | ||||||
|   $: address_city_value = ""; |   $: address_city_value = ""; | ||||||
|   $: address_checked = true; |   $: address_checked = false; | ||||||
|  |  | ||||||
|   let address_input1; |   let address_input1; | ||||||
|   let address_input2; |   let address_input2; | ||||||
| @@ -82,14 +82,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -102,15 +102,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -124,18 +124,18 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("create-a-new-organization")} |                 {$_("create-a-new-organization")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "please-provide-the-required-information-to-add-a-new-organization" |                     "please-provide-the-required-information-to-add-a-new-organization" | ||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="firstname" |                     for="firstname" | ||||||
| @@ -153,7 +153,7 @@ | |||||||
|                     bind:this={name_input_dom} |                     bind:this={name_input_dom} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="firstname" |                     name="firstname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isOrgnameValid} |                   {#if !isOrgnameValid} | ||||||
|                     <span |                     <span | ||||||
| @@ -174,7 +174,7 @@ | |||||||
|                     /> |                     /> | ||||||
|                   </div> |                   </div> | ||||||
|                   <div class="ml-3 text-sm"> |                   <div class="ml-3 text-sm"> | ||||||
|                     <label for="comments" class="font-medium text-gray-700" |                     <label for="comments" class="font-semibold text-gray-700" | ||||||
|                       >{$_("address")}</label |                       >{$_("address")}</label | ||||||
|                     > |                     > | ||||||
|                   </div> |                   </div> | ||||||
| @@ -196,7 +196,7 @@ | |||||||
|                       bind:this={address_input1} |                       bind:this={address_input1} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="address1" |                       name="address1" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                     {#if !isAddress1Valid} |                     {#if !isAddress1Valid} | ||||||
|                       <span |                       <span | ||||||
| @@ -219,10 +219,10 @@ | |||||||
|                       bind:this={address_input2} |                       bind:this={address_input2} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="address2" |                       name="address2" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                   </div> |                   </div> | ||||||
|                   <div class="col-span-6"> |                   <div class="col-span-2"> | ||||||
|                     <label |                     <label | ||||||
|                       for="zipcode" |                       for="zipcode" | ||||||
|                       class="block text-sm font-medium text-gray-700" |                       class="block text-sm font-medium text-gray-700" | ||||||
| @@ -238,7 +238,7 @@ | |||||||
|                       bind:this={address_zipcode} |                       bind:this={address_zipcode} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="zipcode" |                       name="zipcode" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                     {#if !iszipcodevalid} |                     {#if !iszipcodevalid} | ||||||
|                       <span |                       <span | ||||||
| @@ -248,7 +248,7 @@ | |||||||
|                       </span> |                       </span> | ||||||
|                     {/if} |                     {/if} | ||||||
|                   </div> |                   </div> | ||||||
|                   <div class="col-span-6"> |                   <div class="col-span-4"> | ||||||
|                     <label |                     <label | ||||||
|                       for="city" |                       for="city" | ||||||
|                       class="block text-sm font-medium text-gray-700" |                       class="block text-sm font-medium text-gray-700" | ||||||
| @@ -264,7 +264,7 @@ | |||||||
|                       bind:this={address_city} |                       bind:this={address_city} | ||||||
|                       type="text" |                       type="text" | ||||||
|                       name="city" |                       name="city" | ||||||
|                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                       class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     /> |                     /> | ||||||
|                     {#if !iscityvalid} |                     {#if !iscityvalid} | ||||||
|                       <span |                       <span | ||||||
| @@ -279,13 +279,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("create")} |             {$_("create")} | ||||||
|           </button> |           </button> | ||||||
| @@ -294,7 +294,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -1,108 +0,0 @@ | |||||||
| <script> |  | ||||||
|   import { _ } from "svelte-i18n"; |  | ||||||
|   import { clickOutside } from "../base/outsideclick"; |  | ||||||
|  |  | ||||||
|   import { RunnerOrganizationService } from "@odit/lfk-client-js"; |  | ||||||
|  |  | ||||||
|   import { createEventDispatcher } from "svelte"; |  | ||||||
|   export let modal_open; |  | ||||||
|   export let delete_org; |  | ||||||
|   const dispatch = createEventDispatcher(); |  | ||||||
|   function cancelDelete() { |  | ||||||
|     modal_open = false; |  | ||||||
|     dispatch("cancelDelete", { id: delete_org.id }); |  | ||||||
|   } |  | ||||||
|   function deleteOrg() { |  | ||||||
|     RunnerOrganizationService.runnerOrganizationControllerRemove( |  | ||||||
|       delete_org.id, |  | ||||||
|       true |  | ||||||
|     ) |  | ||||||
|       .then((resp) => { |  | ||||||
|         toast($_("organization-deleted")); |  | ||||||
|         location.replace("./"); |  | ||||||
|       }) |  | ||||||
|       .catch((err) => {}); |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| {#if modal_open} |  | ||||||
|   <div |  | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |  | ||||||
|     use:clickOutside |  | ||||||
|     on:click_outside={cancelDelete} |  | ||||||
|   > |  | ||||||
|     <div |  | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |  | ||||||
|     > |  | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |  | ||||||
|         <div |  | ||||||
|           class="absolute inset-0 bg-gray-500 opacity-75" |  | ||||||
|           data-id="modal_backdrop" |  | ||||||
|         /> |  | ||||||
|       </div> |  | ||||||
|       <span |  | ||||||
|         class="hidden sm:inline-block sm:align-middle sm:h-screen" |  | ||||||
|         aria-hidden="true">​</span |  | ||||||
|       > |  | ||||||
|       <div |  | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |  | ||||||
|         role="dialog" |  | ||||||
|         aria-modal="true" |  | ||||||
|         aria-labelledby="modal-headline" |  | ||||||
|       > |  | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |  | ||||||
|           <div class="sm:flex sm:items-start"> |  | ||||||
|             <div |  | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |  | ||||||
|             > |  | ||||||
|               <svg |  | ||||||
|                 class="h-6 w-6 text-blue-600" |  | ||||||
|                 fill="currentColor" |  | ||||||
|                 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 |  | ||||||
|               > |  | ||||||
|             </div> |  | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |  | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |  | ||||||
|                 {$_("attention")} |  | ||||||
|               </h3> |  | ||||||
|               <div class="mt-2 mb-6"> |  | ||||||
|                 <p class="text-sm text-gray-500"> |  | ||||||
|                   {$_( |  | ||||||
|                     "do-you-want-to-delete-the-organization-delete_org-name", |  | ||||||
|                     { |  | ||||||
|                       values: { orgname: delete_org.name }, |  | ||||||
|                     } |  | ||||||
|                   )}<br /> |  | ||||||
|                   {$_("all-associated-teams-and-runners-will-be-deleted-too")} |  | ||||||
|                 </p> |  | ||||||
|               </div> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |  | ||||||
|           <button |  | ||||||
|             on:click={deleteOrg} |  | ||||||
|             type="button" |  | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm" |  | ||||||
|           > |  | ||||||
|             {$_("confirm-delete-organization-and-associated-teams-runners")} |  | ||||||
|           </button> |  | ||||||
|           <button |  | ||||||
|             on:click={cancelDelete} |  | ||||||
|             type="button" |  | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |  | ||||||
|           > |  | ||||||
|             {$_("cancel-keep-organization")} |  | ||||||
|           </button> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| {/if} |  | ||||||
							
								
								
									
										104
									
								
								src/components/orgs/ConfirmOrgDeletionModal.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/components/orgs/ConfirmOrgDeletionModal.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | |||||||
|  | <script> | ||||||
|  | 	import { _ } from "svelte-i18n"; | ||||||
|  | 	import { clickOutside } from "../base/outsideclick"; | ||||||
|  |  | ||||||
|  | 	import { RunnerOrganizationService } from "@odit/lfk-client-js"; | ||||||
|  |  | ||||||
|  | 	import { createEventDispatcher } from "svelte"; | ||||||
|  | 	export let modal_open; | ||||||
|  | 	export let delete_org; | ||||||
|  | 	const dispatch = createEventDispatcher(); | ||||||
|  | 	function cancelDelete() { | ||||||
|  | 		modal_open = false; | ||||||
|  | 		dispatch("cancelDelete", { id: delete_org.id }); | ||||||
|  | 	} | ||||||
|  | 	function deleteOrg() { | ||||||
|  | 		RunnerOrganizationService.runnerOrganizationControllerRemove( | ||||||
|  | 			delete_org.id, | ||||||
|  | 			true | ||||||
|  | 		) | ||||||
|  | 			.then((resp) => { | ||||||
|  | 				toast.success($_("organization-deleted")); | ||||||
|  | 				location.replace("./"); | ||||||
|  | 			}) | ||||||
|  | 			.catch((err) => {}); | ||||||
|  | 	} | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if modal_open} | ||||||
|  | 	<div | ||||||
|  | 		class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|  | 		use:clickOutside | ||||||
|  | 		on:click_outside={cancelDelete} | ||||||
|  | 	> | ||||||
|  | 		<div | ||||||
|  | 			class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|  | 		> | ||||||
|  | 			<div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|  | 				<div | ||||||
|  | 					class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|  | 					data-id="modal_backdrop" | ||||||
|  | 				/> | ||||||
|  | 			</div> | ||||||
|  | 			<span | ||||||
|  | 				class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|  | 				aria-hidden="true">​</span | ||||||
|  | 			> | ||||||
|  | 			<div | ||||||
|  | 				class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|  | 				role="dialog" | ||||||
|  | 				aria-modal="true" | ||||||
|  | 				aria-labelledby="modal-headline" | ||||||
|  | 			> | ||||||
|  | 				<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|  | 					<div class=""> | ||||||
|  | 						<div | ||||||
|  | 							class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|  | 						> | ||||||
|  | 							<svg | ||||||
|  | 								class="h-6 w-6 text-blue-600" | ||||||
|  | 								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 | ||||||
|  | 							> | ||||||
|  | 						</div> | ||||||
|  | 						<div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|  | 							<h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|  | 								{$_("do-you-want-to-delete-the-organization-delete_org-name", { | ||||||
|  | 									values: { orgname: delete_org.name }, | ||||||
|  | 								})} | ||||||
|  | 							</h3> | ||||||
|  | 							<div class="mb-6"> | ||||||
|  | 								<p class="text-sm text-gray-500"> | ||||||
|  | 									{$_("all-associated-teams-and-runners-will-be-deleted-too")} | ||||||
|  | 								</p> | ||||||
|  | 							</div> | ||||||
|  | 						</div> | ||||||
|  | 					</div> | ||||||
|  | 				</div> | ||||||
|  | 				<div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|  | 					<button | ||||||
|  | 						on:click={deleteOrg} | ||||||
|  | 						type="button" | ||||||
|  | 						class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500" | ||||||
|  | 					> | ||||||
|  | 						{$_("confirm-delete-organization-and-associated-teams-runners")} | ||||||
|  | 					</button> | ||||||
|  | 					<button | ||||||
|  | 						on:click={cancelDelete} | ||||||
|  | 						type="button" | ||||||
|  | 						class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|  | 					> | ||||||
|  | 						{$_("cancel-keep-organization")} | ||||||
|  | 					</button> | ||||||
|  | 				</div> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
|  | 	</div> | ||||||
|  | {/if} | ||||||
| @@ -1,482 +1,421 @@ | |||||||
| <script> | <script> | ||||||
|   import { | 	import { | ||||||
|     GroupContactService, | 		GroupContactService, | ||||||
|     RunnerOrganizationService, | 		RunnerOrganizationService, | ||||||
|   } from "@odit/lfk-client-js"; | 	} from "@odit/lfk-client-js"; | ||||||
|   import { getLocaleFromNavigator, _ } from "svelte-i18n"; | 	import toast from "svelte-french-toast"; | ||||||
|  | 	import { _ } from "svelte-i18n"; | ||||||
|   import store from "../../store"; | 	import { tick } from "svelte"; | ||||||
|   import ConfirmOrgDeletion from "./ConfirmOrgDeletion.svelte"; | 	import Select from "svelte-select"; | ||||||
|   import ImportRunnerModal from "../runners/ImportRunnerModal.svelte"; | 	import store from "../../store"; | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; | 	import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   import Select from "svelte-select"; | 	import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|   import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | 	import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte"; | ||||||
|   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | 	import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | ||||||
|   import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte"; | 	import ImportRunnerModal from "../runners/ImportRunnerModal.svelte"; | ||||||
|   import { tick } from "svelte"; | 	import ConfirmOrgDeletionModal from "./ConfirmOrgDeletionModal.svelte"; | ||||||
|   $: delete_triggered = false; | 	$: address_valid_or_none = | ||||||
|   $: address_valid_or_none = | 		(isAddress1Valid && iszipcodevalid && iscityvalid) || | ||||||
|     (isAddress1Valid && iszipcodevalid && iscityvalid) || | 		editable.address_checked === false; | ||||||
|     editable.address_checked === false; | 	$: save_enabled = data_changed && address_valid_or_none; | ||||||
|   $: save_enabled = data_changed && address_valid_or_none; | 	let original = ""; | ||||||
|   let original = ""; | 	let original_object = {}; | ||||||
|   let original_object = {}; | 	let contacts = []; | ||||||
|   let contacts = []; | 	let valueCopy = null; | ||||||
|   let valueCopy = null; | 	let areaDom; | ||||||
|   let areaDom; | 	export let params; | ||||||
|   let copied = false; | 	$: editable = {}; | ||||||
|   export let params; | 	$: contact = {}; | ||||||
|   $: editable = {}; | 	$: data_loaded = false; | ||||||
|   $: contact = {}; | 	$: data_changed = !(JSON.stringify(editable) === original); | ||||||
|   $: data_loaded = false; | 	$: isAddress1Valid = editable.address?.address1?.trim().length !== 0; | ||||||
|   $: data_changed = !(JSON.stringify(editable) === original); | 	$: iszipcodevalid = editable.address?.postalcode?.trim().length !== 0; | ||||||
|   $: isAddress1Valid = editable.address?.address1?.trim().length !== 0; | 	$: iscityvalid = editable.address?.city?.trim().length !== 0; | ||||||
|   $: iszipcodevalid = editable.address?.postalcode?.trim().length !== 0; | 	$: sponsoring_contracts_show = true; | ||||||
|   $: iscityvalid = editable.address?.city?.trim().length !== 0; | 	$: cards_show = true; | ||||||
|   $: sponsoring_contracts_show = true; | 	$: certificates_show = true; | ||||||
|   $: cards_show = true; | 	$: generate_orgs = [original_object]; | ||||||
|   $: certificates_show = true; | 	$: registrationLink = `${config.baseurl_selfservice}/register/${editable.registrationKey}`; | ||||||
|   $: generate_orgs = [original_object]; | 	const getContactLabel = (option) => | ||||||
|   $: registrationLink = `${config.baseurl}/selfservice/register/${editable.registrationKey}`; | 		option.firstname + " " + (option.middlename || "") + " " + option.lastname; | ||||||
|   const getContactLabel = (option) => | 	const promise = RunnerOrganizationService.runnerOrganizationControllerGetOne( | ||||||
|     option.firstname + " " + (option.middlename || "") + " " + option.lastname; | 		params.orgid | ||||||
|   const promise = RunnerOrganizationService.runnerOrganizationControllerGetOne( | 	).then((value) => { | ||||||
|     params.orgid | 		data_loaded = true; | ||||||
|   ).then((value) => { | 		value.address_checked = value.address.address1 !== null; | ||||||
|     data_loaded = true; | 		if (value.address_checked === false) { | ||||||
|     value.address_checked = value.address.address1 !== null; | 			value.address = { | ||||||
|     if (value.address_checked === false) { | 				address1: "", | ||||||
|       value.address = { | 				address2: "", | ||||||
|         address1: "", | 				city: "", | ||||||
|         address2: "", | 				postalcode: "", | ||||||
|         city: "", | 				country: "", | ||||||
|         postalcode: "", | 			}; | ||||||
|         country: "", | 		} | ||||||
|       }; | 		editable = Object.assign(editable, value); | ||||||
|     } | 		editable = editable; | ||||||
|     editable = Object.assign(editable, value); | 		original_object = Object.assign(editable, value); | ||||||
|     editable = editable; | 		original = JSON.stringify(value); | ||||||
|     original_object = Object.assign(editable, value); | 		GroupContactService.groupContactControllerGetAll().then((val) => { | ||||||
|     original = JSON.stringify(value); | 			contacts = val.map((r) => { | ||||||
|     GroupContactService.groupContactControllerGetAll().then((val) => { | 				return { label: getContactLabel(r), value: r }; | ||||||
|       contacts = val.map((r) => { | 			}); | ||||||
|         return { label: getContactLabel(r), value: r }; | 			if (editable.contact) { | ||||||
|       }); | 				contact = contacts.find((g) => g.value.id == editable.contact.id); | ||||||
|       if (editable.contact) { | 			} else { | ||||||
|         contact = contacts.find((g) => g.value.id == editable.contact.id); | 				contact = null; | ||||||
|       } else { | 			} | ||||||
|         contact = null; | 		}); | ||||||
|       } | 	}); | ||||||
|     }); | 	let modal_open = false; | ||||||
|   }); | 	let delete_org = {}; | ||||||
|   let modal_open = false; | 	function deleteOrganization() { | ||||||
|   let delete_org = {}; | 		RunnerOrganizationService.runnerOrganizationControllerRemove( | ||||||
|   function deleteOrganization() { | 			original_object.id, | ||||||
|     RunnerOrganizationService.runnerOrganizationControllerRemove( | 			false | ||||||
|       original_object.id, | 		) | ||||||
|       false | 			.then((resp) => { | ||||||
|     ) | 				toast.success($_("organization-deleted")); | ||||||
|       .then((resp) => { | 				location.replace("./"); | ||||||
|         toast($_("organization-deleted")); | 			}) | ||||||
|         location.replace("./"); | 			.catch((err) => {}); | ||||||
|       }) | 	} | ||||||
|       .catch((err) => { | 	function submit() { | ||||||
|         modal_open = true; | 		if (data_loaded === true && save_enabled) { | ||||||
|         delete_org = original_object; | 			toast($_("updating-organization")); | ||||||
|       }); | 			let postdata = Object.assign({}, editable); | ||||||
|   } | 			if (postdata.address_checked === false) { | ||||||
|   function submit() { | 				postdata.address = null; | ||||||
|     if (data_loaded === true && save_enabled) { | 			} | ||||||
|       toast($_("updating-organization")); | 			postdata.contact = postdata.contact?.id; | ||||||
|       let postdata = Object.assign({}, editable); | 			RunnerOrganizationService.runnerOrganizationControllerPut( | ||||||
|       if (postdata.address_checked === false) { | 				original_object.id, | ||||||
|         postdata.address = null; | 				postdata | ||||||
|       } | 			) | ||||||
|       postdata.contact = postdata.contact?.id; | 				.then((resp) => { | ||||||
|       RunnerOrganizationService.runnerOrganizationControllerPut( | 					editable.registrationKey = resp.registrationKey; | ||||||
|         original_object.id, | 					original_object = Object.assign({}, editable); | ||||||
|         postdata | 					original = JSON.stringify(original_object); | ||||||
|       ) | 					toast.success($_("updated-organization")); | ||||||
|         .then((resp) => { | 				}) | ||||||
|           editable.registrationKey = resp.registrationKey; | 				.catch((err) => {}); | ||||||
|           original_object = Object.assign({}, editable); | 		} else { | ||||||
|           original = JSON.stringify(original_object); | 		} | ||||||
|           toast.success($_("updated-organization")); | 	} | ||||||
|         }) | 	async function copy() { | ||||||
|         .catch((err) => {}); | 		if (!editable.registrationKey) { | ||||||
|     } else { | 			toast.error($_("you-have-to-save-your-changes-to-generate-a-link")); | ||||||
|     } | 			return; | ||||||
|   } | 		} | ||||||
|   async function copy() { | 		valueCopy = registrationLink; | ||||||
|     if (!editable.registrationKey) { | 		await tick(); | ||||||
|       toast.error($_("you-have-to-save-your-changes-to-generate-a-link")); | 		areaDom.focus(); | ||||||
|       return; | 		areaDom.select(); | ||||||
|     } | 		try { | ||||||
|     valueCopy = registrationLink; | 			const successful = document.execCommand("copy"); | ||||||
|     await tick(); | 			if (!successful) { | ||||||
|     areaDom.focus(); | 				throw new Error(); | ||||||
|     areaDom.select(); | 			} | ||||||
|     try { | 			toast($_("copied-link-to-clipboard")); | ||||||
|       const successful = document.execCommand("copy"); | 		} catch (err) { | ||||||
|       if (!successful) { | 			toast.error($_("error-whyile-copying-to-clipboard")); | ||||||
|         throw new Error(); | 		} | ||||||
|       } | 		// we can notifi by event or storage about copy status | ||||||
|       toast($_("copied-link-to-clipboard")); | 		valueCopy = null; | ||||||
|       copied = true; | 	} | ||||||
|     } catch (err) { | 	export let import_modal_open = false; | ||||||
|       toast.error($_("error-whyile-copying-to-clipboard")); |  | ||||||
|     } |  | ||||||
|     // we can notifi by event or storage about copy status |  | ||||||
|     valueCopy = null; |  | ||||||
|   } |  | ||||||
|   export let import_modal_open = false; |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if valueCopy != null}<textarea bind:this={areaDom}>{valueCopy}</textarea>{/if} | {#if valueCopy != null}<textarea bind:this={areaDom}>{valueCopy}</textarea>{/if} | ||||||
| <ImportRunnerModal | <ImportRunnerModal | ||||||
|   on:cancelDelete={(event) => { | 	on:cancelDelete={(event) => { | ||||||
|     import_modal_open = false; | 		import_modal_open = false; | ||||||
|   }} | 	}} | ||||||
|   current_runners={[]} | 	current_runners={[]} | ||||||
|   passed_team={{}} | 	passed_team={{}} | ||||||
|   passed_orgs={[]} | 	passed_orgs={[]} | ||||||
|   passed_org={editable} | 	passed_org={editable} | ||||||
|   opened_from="OrgDetail" | 	opened_from="OrgDetail" | ||||||
|   bind:import_modal_open | 	bind:import_modal_open | ||||||
| /> | /> | ||||||
| <ConfirmOrgDeletion bind:modal_open bind:delete_org /> | <ConfirmOrgDeletionModal bind:modal_open bind:delete_org /> | ||||||
| {#if data_loaded} | {#if data_loaded} | ||||||
|   <section class="container p-5"> | 	<section class="container p-5"> | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> | 		<div class="flex flex-row mb-4"> | ||||||
|       {original_object.name} | 			<div class="w-full"> | ||||||
|       <span data-id="org_actions_${editable.id}"> | 				<nav class="w-full flex"> | ||||||
|         <GenerateSponsoringContracts | 					<ol class="list-none flex flex-row items-center justify-start"> | ||||||
|           bind:sponsoring_contracts_show | 						<li class="flex items-center"> | ||||||
|           bind:generate_orgs | 							<a class="mr-2" href="./" | ||||||
|         /> | 								><svg | ||||||
|         <GenerateRunnerCards bind:cards_show bind:generate_orgs /> | 									xmlns="http://www.w3.org/2000/svg" | ||||||
|         <GenerateRunnerCertificates bind:certificates_show bind:generate_orgs /> | 									width="24" | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:IMPORT")} | 									height="24" | ||||||
|           <button | 									viewBox="0 0 24 24" | ||||||
|             on:click={() => { | 									fill="none" | ||||||
|               import_modal_open = true; | 									stroke="currentColor" | ||||||
|             }} | 									stroke-width="2" | ||||||
|             type="button" | 									stroke-linecap="round" | ||||||
|             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" | 									stroke-linejoin="round" | ||||||
|           > | 									class="inline-block" | ||||||
|             {$_("import-runners")} | 									><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg | ||||||
|           </button> | 								> | ||||||
|         {/if} | 								{$_("organizations")}</a | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:DELETE")} | 							> | ||||||
|           {#if delete_triggered} | 						</li> | ||||||
|             <button | 					</ol> | ||||||
|               on:click={deleteOrganization} | 				</nav> | ||||||
|               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" | 			</div> | ||||||
|               >{$_("confirm-delete")}</button | 		</div> | ||||||
|             > | 		<div class="mb-4 text-3xl font-extrabold leading-tight"> | ||||||
|             <button | 			{original_object.name} [#{params.orgid}] | ||||||
|               on:click={() => { | 			<div data-id="org_actions_${editable.id}"> | ||||||
|                 delete_triggered = !delete_triggered; | 				<GenerateSponsoringContracts | ||||||
|               }} | 					bind:sponsoring_contracts_show | ||||||
|               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" | 					bind:generate_orgs | ||||||
|               >{$_("cancel")}</button | 				/> | ||||||
|             > | 				<GenerateRunnerCards bind:cards_show bind:generate_orgs /> | ||||||
|           {/if} | 				<GenerateRunnerCertificates bind:certificates_show bind:generate_orgs /> | ||||||
|           {#if !delete_triggered} | 				{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:IMPORT")} | ||||||
|             <button | 					<button | ||||||
|               on:click={() => { | 						on:click={() => { | ||||||
|                 delete_triggered = true; | 							import_modal_open = true; | ||||||
|               }} | 						}} | ||||||
|               type="button" | 						type="button" | ||||||
|               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm" | 						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:w-auto sm:text-sm" | ||||||
|               >{$_("delete-organization")}</button | 					> | ||||||
|             > | 						{$_("import-runners")} | ||||||
|           {/if} | 					</button> | ||||||
|         {/if} | 				{/if} | ||||||
|         {#if !delete_triggered} | 				{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:DELETE")} | ||||||
|           <button | 					<button | ||||||
|             on:click={submit} | 						on:click={() => { | ||||||
|             disabled={!save_enabled} | 							modal_open = true; | ||||||
|             class:opacity-50={!save_enabled} | 							delete_org = original_object; | ||||||
|             type="button" | 						}} | ||||||
|             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" | 						type="button" | ||||||
|             >{$_("save-changes")}</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:w-auto sm:text-sm" | ||||||
|           > | 						>{$_("delete-organization")}</button | ||||||
|         {/if} | 					> | ||||||
|       </span> | 				{/if} | ||||||
|     </div> | 				<button | ||||||
|     <div class="flex flex-row mb-4"> | 					on:click={submit} | ||||||
|       <div class="w-full"> | 					disabled={!save_enabled} | ||||||
|         <nav class="w-full flex"> | 					class:opacity-50={!save_enabled} | ||||||
|           <ol class="list-none flex flex-row items-center justify-start"> | 					type="button" | ||||||
|             <li class="mr-2 flex items-center"> | 					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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|               <svg | 					>{$_("save-changes")}</button | ||||||
|                 stroke="currentColor" | 				> | ||||||
|                 fill="none" | 			</div> | ||||||
|                 stroke-width="2" | 		</div> | ||||||
|                 viewBox="0 0 24 24" | 		<div class="text-sm w-full mt-2"> | ||||||
|                 stroke-linecap="round" | 			<label for="name" class="font-semibold text-gray-700">{$_("name")}</label> | ||||||
|                 stroke-linejoin="round" | 			<input | ||||||
|                 class="h-3 w-3 stroke-current" | 				autocomplete="off" | ||||||
|                 height="1em" | 				placeholder={$_("name")} | ||||||
|                 width="1em" | 				type="text" | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 				bind:value={editable.name} | ||||||
|                 ><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /> | 				name="name" | ||||||
|                 <polyline points="9 22 9 12 15 12 15 22" /></svg | 				class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|               > | 			/> | ||||||
|             </li> | 		</div> | ||||||
|             <li class="flex items-center"> | 		<div class="text-sm w-full mt-2"> | ||||||
|               <a class="mr-2" href="/">{$_("home")}</a><svg | 			<label for="contact" class="font-semibold text-gray-700" | ||||||
|                 stroke="currentColor" | 				>{$_("contact")}</label | ||||||
|                 fill="none" | 			> | ||||||
|                 stroke-width="2" | 			<Select | ||||||
|                 viewBox="0 0 24 24" | 				containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                 stroke-linecap="round" | 				itemFilter={(label, filterText, option) => | ||||||
|                 stroke-linejoin="round" | 					label.toLowerCase().includes(filterText.toLowerCase()) || | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" | 					option.value.id.toString().startsWith(filterText.toLowerCase())} | ||||||
|                 height="1em" | 				items={contacts} | ||||||
|                 width="1em" | 				showChevron={true} | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 				placeholder={$_("no-contact-selected")} | ||||||
|                 ><line x1="5" y1="12" x2="19" y2="12" /> | 				noOptionsMessage={$_("no-contact-found")} | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg | 				bind:selectedValue={contact} | ||||||
|               > | 				on:select={(selectedValue) => | ||||||
|             </li> | 					(editable.contact = selectedValue.detail.value)} | ||||||
|             <li class="mr-2 flex items-center"> | 				on:clear={() => (editable.contact = null)} | ||||||
|               <svg | 			/> | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 		</div> | ||||||
|                 viewBox="0 0 24 24" | 		<div> | ||||||
|                 width="24" | 			<div class="flex items-start mt-2"> | ||||||
|                 height="24" | 				<div class="flex items-center h-5"> | ||||||
|                 ><path fill="none" d="M0 0h24v24H0z" /> | 					<input | ||||||
|                 <path | 						bind:checked={editable.registrationEnabled} | ||||||
|                   d="M21 20h2v2H1v-2h2V3a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v17zm-2 0V4H5v16h14zM8 11h3v2H8v-2zm0-4h3v2H8V7zm0 8h3v2H8v-2zm5 0h3v2h-3v-2zm0-4h3v2h-3v-2zm0-4h3v2h-3V7z" | 						id="toggle_selfservice_feature" | ||||||
|                 /></svg | 						name="toggle_selfservice_feature" | ||||||
|               > | 						type="checkbox" | ||||||
|             </li> | 						class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||||||
|             <li class="flex items-center"> | 					/> | ||||||
|               <a class="mr-2" href="./">{$_("organizations")}</a><svg | 				</div> | ||||||
|                 stroke="currentColor" | 				<div class="ml-3 text-sm"> | ||||||
|                 fill="none" | 					<label | ||||||
|                 stroke-width="2" | 						for="toggle_selfservice_feature" | ||||||
|                 viewBox="0 0 24 24" | 						class="font-semibold text-gray-700" | ||||||
|                 stroke-linecap="round" | 						>{$_("selfservice-registration")}</label | ||||||
|                 stroke-linejoin="round" | 					> | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" | 				</div> | ||||||
|                 height="1em" | 			</div> | ||||||
|                 width="1em" | 			<div> | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 				{#if editable.registrationEnabled} | ||||||
|                 ><line x1="5" y1="12" x2="19" y2="12" /> | 					<div class="text-sm w-full mt-2"> | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg | 						<button on:click={copy} class="inline-flex w-full"> | ||||||
|               > | 							<p | ||||||
|             </li> | 								name="token" | ||||||
|             <li class="flex items-center"> | 								class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 p-2 break-all font-mono text-left" | ||||||
|               <span class="mr-2">Org-Details #{params.orgid}</span> | 							> | ||||||
|             </li> | 								{#if editable.registrationKey} | ||||||
|           </ol> | 									{registrationLink} | ||||||
|         </nav> | 								{:else} | ||||||
|       </div> | 									{$_("you-have-to-save-your-changes-to-generate-a-link")} | ||||||
|     </div> | 								{/if} | ||||||
|     <div class="text-sm w-full"> | 							</p> | ||||||
|       <label for="name" class="font-medium text-gray-700">{$_("name")}</label> | 							<div | ||||||
|       <input | 								class="bg-gray-200 border-gray-300 border-t border-b border-r text-black rounded-r-md sm:text-sm p-2 cursor-pointer flex items-center justify-center" | ||||||
|         autocomplete="off" | 							> | ||||||
|         placeholder={$_("name")} | 								<svg | ||||||
|         type="text" | 									xmlns="http://www.w3.org/2000/svg" | ||||||
|         bind:value={editable.name} | 									viewBox="0 0 24 24" | ||||||
|         name="name" | 									width="24" | ||||||
|         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" | 									height="24" | ||||||
|       /> | 									><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|     </div> | 									<path | ||||||
|     <div class="text-sm w-full"> | 										fill="currentColor" | ||||||
|       <label for="contact" class="font-medium text-gray-700" | 										d="M7 4V2h10v2h3l1 1v16a1 1 0 01-1 1H4a1 1 0 01-1-1V5l1-1h3zm0 2H5v14h14V6h-2v2H7V6zm2-2v2h6V4H9z" | ||||||
|         >{$_("contact")}</label | 									/></svg | ||||||
|       > | 								> | ||||||
|       <Select | 							</div> | ||||||
|         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" | 						</button> | ||||||
|         itemFilter={(label, filterText, option) => | 						{#if editable.registrationKey} | ||||||
|           label.toLowerCase().includes(filterText.toLowerCase()) || | 							<p class="text-gray-500 text-xs"> | ||||||
|           option.value.id.toString().startsWith(filterText.toLowerCase())} | 								{$_("click-to-copy-the-link-into-your-clipboard")} | ||||||
|         items={contacts} | 							</p> | ||||||
|         showChevron={true} | 						{/if} | ||||||
|         placeholder={$_("no-contact-selected")} | 					</div> | ||||||
|         noOptionsMessage={$_("no-contact-found")} | 				{/if} | ||||||
|         bind:selectedValue={contact} | 				<!--  --> | ||||||
|         on:select={(selectedValue) => | 				<div> | ||||||
|           (editable.contact = selectedValue.detail.value)} | 					<div class="flex items-start mt-2"> | ||||||
|         on:clear={() => (editable.contact = null)} | 						<div class="flex items-center h-5"> | ||||||
|       /> | 							<input | ||||||
|     </div> | 								bind:checked={editable.address_checked} | ||||||
|     <div> | 								id="toggle_address_checkbox" | ||||||
|       <div class="flex items-start mt-2"> | 								name="toggle_address_checkbox" | ||||||
|         <div class="flex items-center h-5"> | 								type="checkbox" | ||||||
|           <input | 								class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||||||
|             bind:checked={editable.registrationEnabled} | 							/> | ||||||
|             id="toggle_selfservice_feature" | 						</div> | ||||||
|             name="toggle_selfservice_feature" | 						<div class="ml-3 text-sm"> | ||||||
|             type="checkbox" | 							<label | ||||||
|             class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | 								for="toggle_address_checkbox" | ||||||
|           /> | 								class="font-semibold text-gray-700">{$_("address")}</label | ||||||
|         </div> | 							> | ||||||
|         <div class="ml-3 text-sm"> | 						</div> | ||||||
|           <label | 					</div> | ||||||
|             for="toggle_selfservice_feature" | 				</div> | ||||||
|             class="font-medium text-gray-700" | 				{#if editable.address_checked === true} | ||||||
|             >{$_("selfservice-registration")}</label | 					<div class="col-span-6"> | ||||||
|           > | 						<label | ||||||
|         </div> | 							for="address1" | ||||||
|       </div> | 							class="block text-sm font-medium text-gray-700" | ||||||
|       <div> | 							>{$_("address")}</label | ||||||
|         {#if editable.registrationEnabled} | 						> | ||||||
|           <div class="text-sm w-full"> | 						<input | ||||||
|             <button on:click={copy} class="inline-flex w-full"> | 							autocomplete="off" | ||||||
|               <p | 							placeholder="Address" | ||||||
|                 name="token" | 							class:border-red-500={!isAddress1Valid} | ||||||
|                 class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 p-2" | 							class:focus:border-red-500={!isAddress1Valid} | ||||||
|               > | 							class:focus:ring-red-500={!isAddress1Valid} | ||||||
|                 {#if editable.registrationKey} | 							bind:value={editable.address.address1} | ||||||
|                   {registrationLink} | 							type="text" | ||||||
|                 {:else} | 							name="address1" | ||||||
|                   {$_("you-have-to-save-your-changes-to-generate-a-link")} | 							class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                 {/if} | 						/> | ||||||
|               </p> | 						{#if !isAddress1Valid} | ||||||
|               <div | 							<span | ||||||
|                 class="bg-gray-200 border-gray-300 border-t border-b border-r text-black rounded-r-md sm:text-sm p-2 mt-1 cursor-pointer" | 								class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|               > | 							> | ||||||
|                 <svg | 								{$_("address-is-required")} | ||||||
|                   xmlns="http://www.w3.org/2000/svg" | 							</span> | ||||||
|                   viewBox="0 0 24 24" | 						{/if} | ||||||
|                   width="24" | 					</div> | ||||||
|                   height="24" | 					<div class="col-span-6"> | ||||||
|                   ><path fill="none" d="M0 0h24v24H0z" /> | 						<label | ||||||
|                   <path | 							for="address2" | ||||||
|                     fill="currentColor" | 							class="block text-sm font-medium text-gray-700" | ||||||
|                     d="M7 4V2h10v2h3l1 1v16a1 1 0 01-1 1H4a1 1 0 01-1-1V5l1-1h3zm0 2H5v14h14V6h-2v2H7V6zm2-2v2h6V4H9z" | 							>{$_("apartment-suite-etc")}</label | ||||||
|                   /></svg | 						> | ||||||
|                 > | 						<input | ||||||
|               </div> | 							autocomplete="off" | ||||||
|             </button> | 							placeholder={$_("apartment-suite-etc")} | ||||||
|             {#if editable.registrationKey} | 							bind:value={editable.address.address2} | ||||||
|               <p class="text-gray-500 text-xs"> | 							type="text" | ||||||
|                 {$_("click-to-copy-the-link-into-your-clipboard")} | 							name="address2" | ||||||
|               </p> | 							class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|             {/if} | 						/> | ||||||
|           </div> | 					</div> | ||||||
|         {/if} | 					<div class="col-span-6"> | ||||||
|         <!--  --> | 						<label for="zipcode" class="block text-sm font-medium text-gray-700" | ||||||
|         <div> | 							>{$_("zip-postal-code")}</label | ||||||
|           <div class="flex items-start mt-2"> | 						> | ||||||
|             <div class="flex items-center h-5"> | 						<input | ||||||
|               <input | 							autocomplete="off" | ||||||
|                 bind:checked={editable.address_checked} | 							placeholder={$_("zip-postal-code")} | ||||||
|                 id="toggle_address_checkbox" | 							class:border-red-500={!iszipcodevalid} | ||||||
|                 name="toggle_address_checkbox" | 							class:focus:border-red-500={!iszipcodevalid} | ||||||
|                 type="checkbox" | 							class:focus:ring-red-500={!iszipcodevalid} | ||||||
|                 class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | 							bind:value={editable.address.postalcode} | ||||||
|               /> | 							type="text" | ||||||
|             </div> | 							name="zipcode" | ||||||
|             <div class="ml-3 text-sm"> | 							class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|               <label | 						/> | ||||||
|                 for="toggle_address_checkbox" | 						{#if !iszipcodevalid} | ||||||
|                 class="font-medium text-gray-700">{$_("address")}</label | 							<span | ||||||
|               > | 								class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|             </div> | 							> | ||||||
|           </div> | 								{$_("valid-zipcode-postal-code-is-required")} | ||||||
|         </div> | 							</span> | ||||||
|         {#if editable.address_checked === true} | 						{/if} | ||||||
|           <div class="col-span-6"> | 					</div> | ||||||
|             <label | 					<div class="col-span-6"> | ||||||
|               for="address1" | 						<label for="city" class="block text-sm font-medium text-gray-700" | ||||||
|               class="block text-sm font-medium text-gray-700" | 							>{$_("city")}</label | ||||||
|               >{$_("address")}</label | 						> | ||||||
|             > | 						<input | ||||||
|             <input | 							autocomplete="off" | ||||||
|               autocomplete="off" | 							placeholder={$_("city")} | ||||||
|               placeholder="Address" | 							class:border-red-500={!iscityvalid} | ||||||
|               class:border-red-500={!isAddress1Valid} | 							class:focus:border-red-500={!iscityvalid} | ||||||
|               class:focus:border-red-500={!isAddress1Valid} | 							class:focus:ring-red-500={!iscityvalid} | ||||||
|               class:focus:ring-red-500={!isAddress1Valid} | 							bind:value={editable.address.city} | ||||||
|               bind:value={editable.address.address1} | 							type="text" | ||||||
|               type="text" | 							name="city" | ||||||
|               name="address1" | 							class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|               class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 						/> | ||||||
|             /> | 						{#if !iscityvalid} | ||||||
|             {#if !isAddress1Valid} | 							<span | ||||||
|               <span | 								class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|                 class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 							> | ||||||
|               > | 								{$_("valid-city-is-required")} | ||||||
|                 {$_("address-is-required")} | 							</span> | ||||||
|               </span> | 						{/if} | ||||||
|             {/if} | 					</div> | ||||||
|           </div> | 				{/if} | ||||||
|           <div class="col-span-6"> | 				<div class="text-sm w-full mt-2"> | ||||||
|             <label | 					<span class="font-semibold text-gray-700">{$_("distance")}</span> | ||||||
|               for="address2" | 					<br /> | ||||||
|               class="block text-sm font-medium text-gray-700" | 					<span class="text-gray-700" | ||||||
|               >{$_("apartment-suite-etc")}</label | 						>{(original_object.total_distance / 1000).toFixed(2)} km</span | ||||||
|             > | 					> | ||||||
|             <input | 				</div> | ||||||
|               autocomplete="off" | 			</div> | ||||||
|               placeholder={$_("apartment-suite-etc")} | 		</div> | ||||||
|               bind:value={editable.address.address2} | 	</section> | ||||||
|               type="text" |  | ||||||
|               name="address2" |  | ||||||
|               class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |  | ||||||
|             /> |  | ||||||
|           </div> |  | ||||||
|           <div class="col-span-6"> |  | ||||||
|             <label for="zipcode" class="block text-sm font-medium text-gray-700" |  | ||||||
|               >{$_("zip-postal-code")}</label |  | ||||||
|             > |  | ||||||
|             <input |  | ||||||
|               autocomplete="off" |  | ||||||
|               placeholder={$_("zip-postal-code")} |  | ||||||
|               class:border-red-500={!iszipcodevalid} |  | ||||||
|               class:focus:border-red-500={!iszipcodevalid} |  | ||||||
|               class:focus:ring-red-500={!iszipcodevalid} |  | ||||||
|               bind:value={editable.address.postalcode} |  | ||||||
|               type="text" |  | ||||||
|               name="zipcode" |  | ||||||
|               class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |  | ||||||
|             /> |  | ||||||
|             {#if !iszipcodevalid} |  | ||||||
|               <span |  | ||||||
|                 class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" |  | ||||||
|               > |  | ||||||
|                 {$_("valid-zipcode-postal-code-is-required")} |  | ||||||
|               </span> |  | ||||||
|             {/if} |  | ||||||
|           </div> |  | ||||||
|           <div class="col-span-6"> |  | ||||||
|             <label for="city" class="block text-sm font-medium text-gray-700" |  | ||||||
|               >{$_("city")}</label |  | ||||||
|             > |  | ||||||
|             <input |  | ||||||
|               autocomplete="off" |  | ||||||
|               placeholder={$_("city")} |  | ||||||
|               class:border-red-500={!iscityvalid} |  | ||||||
|               class:focus:border-red-500={!iscityvalid} |  | ||||||
|               class:focus:ring-red-500={!iscityvalid} |  | ||||||
|               bind:value={editable.address.city} |  | ||||||
|               type="text" |  | ||||||
|               name="city" |  | ||||||
|               class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |  | ||||||
|             /> |  | ||||||
|             {#if !iscityvalid} |  | ||||||
|               <span |  | ||||||
|                 class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" |  | ||||||
|               > |  | ||||||
|                 {$_("valid-city-is-required")} |  | ||||||
|               </span> |  | ||||||
|             {/if} |  | ||||||
|           </div> |  | ||||||
|         {/if} |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </section> |  | ||||||
| {:else} | {:else} | ||||||
|   {#await promise} | 	{#await promise} | ||||||
|     {$_("organization-detail-is-being-loaded")} | 		{$_("organization-detail-is-being-loaded")} | ||||||
|   {:catch error} | 	{:catch error} | ||||||
|     <PromiseError /> | 		<PromiseError /> | ||||||
|   {/await} | 	{/await} | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -1,250 +0,0 @@ | |||||||
| <script> |  | ||||||
|   import { _ } from "svelte-i18n"; |  | ||||||
|   import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; |  | ||||||
|   let modal_open = false; |  | ||||||
|   let delete_org = {}; |  | ||||||
|   import { RunnerOrganizationService } from "@odit/lfk-client-js"; |  | ||||||
|   import store from "../../store"; |  | ||||||
|   import OrgsEmptyState from "./OrgsEmptyState.svelte"; |  | ||||||
|   import ConfirmOrgDeletion from "./ConfirmOrgDeletion.svelte"; |  | ||||||
|   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; |  | ||||||
|   import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte"; |  | ||||||
|   import toast from "svelte-french-toast"; |  | ||||||
|   $: searchvalue = ""; |  | ||||||
|   $: active_deletes = []; |  | ||||||
|   $: sponsoring_contracts_show = current_organizations.some( |  | ||||||
|     (r) => r.is_selected === true |  | ||||||
|   ); |  | ||||||
|   $: cards_show = current_organizations.some((r) => r.is_selected === true); |  | ||||||
|   $: generate_orgs = current_organizations.filter( |  | ||||||
|     (r) => r.is_selected === true |  | ||||||
|   ); |  | ||||||
|   $: certificates_show = current_organizations.some( |  | ||||||
|     (r) => r.is_selected === true |  | ||||||
|   ); |  | ||||||
|   export let current_organizations = []; |  | ||||||
|  |  | ||||||
|   const promise = |  | ||||||
|     RunnerOrganizationService.runnerOrganizationControllerGetAll().then( |  | ||||||
|       (val) => { |  | ||||||
|         current_organizations = val; |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <ConfirmOrgDeletion |  | ||||||
|   on:cancelDelete={(event) => { |  | ||||||
|     modal_open = false; |  | ||||||
|     active_deletes[event.detail.id] = false; |  | ||||||
|   }} |  | ||||||
|   bind:modal_open |  | ||||||
|   bind:delete_org |  | ||||||
| /> |  | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes("ORGANIZATION:GET")} |  | ||||||
|   {#await promise} |  | ||||||
|     <div |  | ||||||
|       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" |  | ||||||
|       role="alert" |  | ||||||
|     > |  | ||||||
|       <p class="font-bold">{$_("organizations-are-being-loaded")}</p> |  | ||||||
|       <p class="text-sm">{$_("this-might-take-a-moment")}</p> |  | ||||||
|     </div> |  | ||||||
|   {:then} |  | ||||||
|     {#if current_organizations.length === 0} |  | ||||||
|       <OrgsEmptyState /> |  | ||||||
|     {:else} |  | ||||||
|       <input |  | ||||||
|         type="search" |  | ||||||
|         bind:value={searchvalue} |  | ||||||
|         placeholder={$_("datatable.search")} |  | ||||||
|         aria-label={$_("datatable.search")} |  | ||||||
|         class="mb-4" |  | ||||||
|       /> |  | ||||||
|       <div class="h-12"> |  | ||||||
|         <GenerateSponsoringContracts |  | ||||||
|           bind:sponsoring_contracts_show |  | ||||||
|           bind:generate_orgs |  | ||||||
|         /> |  | ||||||
|         <GenerateRunnerCards bind:cards_show bind:generate_orgs /> |  | ||||||
|         <GenerateRunnerCertificates bind:certificates_show bind:generate_orgs /> |  | ||||||
|       </div> |  | ||||||
|       <div |  | ||||||
|         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll" |  | ||||||
|       > |  | ||||||
|         <table class="divide-y divide-gray-200 w-full"> |  | ||||||
|           <thead class="bg-gray-50"> |  | ||||||
|             <tr class="odd:bg-white even:bg-gray-100"> |  | ||||||
|               <th |  | ||||||
|                 scope="col" |  | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" |  | ||||||
|               > |  | ||||||
|                 <button |  | ||||||
|                   on:click={() => { |  | ||||||
|                     const newstate = !current_organizations.some( |  | ||||||
|                       (r) => r.is_selected === true |  | ||||||
|                     ); |  | ||||||
|                     current_organizations = current_organizations.map((r) => { |  | ||||||
|                       r.is_selected = newstate; |  | ||||||
|                       return r; |  | ||||||
|                     }); |  | ||||||
|                   }} |  | ||||||
|                   class="underline cursor-pointer select-none" |  | ||||||
|                   >{#if current_organizations.some((r) => r.is_selected === true)} |  | ||||||
|                     {$_("deselect-all")} |  | ||||||
|                   {:else}{$_("select-all")}{/if} |  | ||||||
|                 </button> |  | ||||||
|               </th> |  | ||||||
|               <th |  | ||||||
|                 scope="col" |  | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" |  | ||||||
|               > |  | ||||||
|                 {$_("name")} |  | ||||||
|               </th> |  | ||||||
|               <th |  | ||||||
|                 scope="col" |  | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" |  | ||||||
|               > |  | ||||||
|                 {$_("address")} |  | ||||||
|               </th> |  | ||||||
|               <th |  | ||||||
|                 scope="col" |  | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" |  | ||||||
|               > |  | ||||||
|                 {$_("contact")} |  | ||||||
|               </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_organizations as o} |  | ||||||
|               {#if Object.values(o) |  | ||||||
|                 .toString() |  | ||||||
|                 .toLowerCase() |  | ||||||
|                 .includes(searchvalue)} |  | ||||||
|                 <tr |  | ||||||
|                   class="odd:bg-white even:bg-gray-100" |  | ||||||
|                   data-rowid="org_{o.id}" |  | ||||||
|                 > |  | ||||||
|                   <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={() => { |  | ||||||
|                           toast.loading($_("deleting-organization")); |  | ||||||
|                           RunnerOrganizationService.runnerOrganizationControllerRemove( |  | ||||||
|                             o.id, |  | ||||||
|                             false |  | ||||||
|                           ) |  | ||||||
|                             .then((resp) => { |  | ||||||
|                               current_organizations = |  | ||||||
|                                 current_organizations.filter( |  | ||||||
|                                   (obj) => obj.id !== o.id |  | ||||||
|                                 ); |  | ||||||
|                               toast($_("organization-deleted")); |  | ||||||
|                             }) |  | ||||||
|                             .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} |  | ||||||
| @@ -1,54 +1,253 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | ||||||
|   import store from "../../store"; | 	let delete_org = {}; | ||||||
|   import AddOrgModal from "./AddOrgModal.svelte"; | 	import { RunnerOrganizationService } from "@odit/lfk-client-js"; | ||||||
|   export let modal_open = false; | 	import store from "../../store"; | ||||||
|   import OrgOverview from "./OrgOverview.svelte"; | 	import OrgsEmptyState from "./OrgsEmptyState.svelte"; | ||||||
|   import ImportRunnerModal from "../runners/ImportRunnerModal.svelte"; | 	import ConfirmOrgDeletionModal from "./ConfirmOrgDeletionModal.svelte"; | ||||||
|   let current_organizations = []; | 	import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|   export let import_modal_open = false; | 	import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte"; | ||||||
|  | 	import toast from "svelte-french-toast"; | ||||||
|  | 	$: searchvalue = ""; | ||||||
|  | 	$: active_deletes = []; | ||||||
|  | 	$: sponsoring_contracts_show = current_organizations.some( | ||||||
|  | 		(r) => r.is_selected === true | ||||||
|  | 	); | ||||||
|  | 	$: cards_show = current_organizations.some((r) => r.is_selected === true); | ||||||
|  | 	$: generate_orgs = current_organizations.filter( | ||||||
|  | 		(r) => r.is_selected === true | ||||||
|  | 	); | ||||||
|  | 	$: certificates_show = current_organizations.some( | ||||||
|  | 		(r) => r.is_selected === true | ||||||
|  | 	); | ||||||
|  | 	let current_organizations = []; | ||||||
|  |  | ||||||
|  | 	const promise = | ||||||
|  | 		RunnerOrganizationService.runnerOrganizationControllerGetAll().then( | ||||||
|  | 			(val) => { | ||||||
|  | 				current_organizations = val; | ||||||
|  | 			} | ||||||
|  | 		); | ||||||
|  | 	import { _ } from "svelte-i18n"; | ||||||
|  | 	import AddOrgModal from "./AddOrgModal.svelte"; | ||||||
|  | 	let delete_modal_open = false; | ||||||
|  | 	let modal_open = false; | ||||||
|  | 	import ImportRunnerModal from "../runners/ImportRunnerModal.svelte"; | ||||||
|  | 	let import_modal_open = false; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> | 	<h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_("organizations")} | 		{$_("organizations")} | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("ORGANIZATION:CREATE")} | 	</h4> | ||||||
|       <button | 	{#if store.state.jwtinfo.userdetails.permissions.includes("ORGANIZATION:CREATE")} | ||||||
|         on:click={() => { | 		<button | ||||||
|           modal_open = true; | 			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" | 			type="button" | ||||||
|       > | 			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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|         {$_("create-organization")} | 		> | ||||||
|       </button> | 			{$_("create-organization")} | ||||||
|     {/if} | 		</button> | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:IMPORT")} | 	{/if} | ||||||
|       <button | 	{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:IMPORT")} | ||||||
|         on:click={() => { | 		<button | ||||||
|           import_modal_open = true; | 			on:click={() => { | ||||||
|         }} | 				import_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" | 			type="button" | ||||||
|       > | 			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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|         {$_("import-runners")} | 		> | ||||||
|       </button> | 			{$_("import-runners")} | ||||||
|     {/if} | 		</button> | ||||||
|   </span> | 	{/if} | ||||||
|   <OrgOverview bind:current_organizations /> | 	<ConfirmOrgDeletionModal | ||||||
|  | 		on:cancelDelete={(event) => { | ||||||
|  | 			delete_modal_open = false; | ||||||
|  | 			active_deletes[event.detail.id] = false; | ||||||
|  | 		}} | ||||||
|  | 		bind:modal_open={delete_modal_open} | ||||||
|  | 		bind:delete_org | ||||||
|  | 	/> | ||||||
|  | 	{#if store.state.jwtinfo.userdetails.permissions.includes("ORGANIZATION:GET")} | ||||||
|  | 		{#await promise} | ||||||
|  | 			<div | ||||||
|  | 				class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|  | 				role="alert" | ||||||
|  | 			> | ||||||
|  | 				<p class="font-bold">{$_("organizations-are-being-loaded")}</p> | ||||||
|  | 				<p class="text-sm">{$_("this-might-take-a-moment")}</p> | ||||||
|  | 			</div> | ||||||
|  | 		{:then} | ||||||
|  | 			{#if current_organizations.length === 0} | ||||||
|  | 				<OrgsEmptyState /> | ||||||
|  | 			{:else} | ||||||
|  | 				<input | ||||||
|  | 					type="search" | ||||||
|  | 					bind:value={searchvalue} | ||||||
|  | 					placeholder={$_("datatable.search")} | ||||||
|  | 					aria-label={$_("datatable.search")} | ||||||
|  | 					class="w-full sm:w-auto sm:mt-0 p-2 rounded-md border mb-1 lg:mb-0" | ||||||
|  | 				/> | ||||||
|  | 				<GenerateSponsoringContracts | ||||||
|  | 					bind:sponsoring_contracts_show | ||||||
|  | 					bind:generate_orgs | ||||||
|  | 				/> | ||||||
|  | 				<GenerateRunnerCards bind:cards_show bind:generate_orgs /> | ||||||
|  | 				<GenerateRunnerCertificates bind:certificates_show bind:generate_orgs /> | ||||||
|  | 				<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 class="odd:bg-white even:bg-gray-100"> | ||||||
|  | 								<th | ||||||
|  | 									scope="col" | ||||||
|  | 									class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|  | 								> | ||||||
|  | 									<button | ||||||
|  | 										on:click={() => { | ||||||
|  | 											const newstate = !current_organizations.some( | ||||||
|  | 												(r) => r.is_selected === true | ||||||
|  | 											); | ||||||
|  | 											current_organizations = current_organizations.map((r) => { | ||||||
|  | 												r.is_selected = newstate; | ||||||
|  | 												return r; | ||||||
|  | 											}); | ||||||
|  | 										}} | ||||||
|  | 										class="underline cursor-pointer select-none" | ||||||
|  | 										>{#if current_organizations.some((r) => r.is_selected === true)} | ||||||
|  | 											{$_("deselect-all")} | ||||||
|  | 										{:else}{$_("select-all")}{/if} | ||||||
|  | 									</button> | ||||||
|  | 								</th> | ||||||
|  | 								<th | ||||||
|  | 									scope="col" | ||||||
|  | 									class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|  | 								> | ||||||
|  | 									{$_("name")} | ||||||
|  | 								</th> | ||||||
|  | 								<th | ||||||
|  | 									scope="col" | ||||||
|  | 									class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|  | 								> | ||||||
|  | 									{$_("address")} | ||||||
|  | 								</th> | ||||||
|  | 								<th | ||||||
|  | 									scope="col" | ||||||
|  | 									class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|  | 								> | ||||||
|  | 									{$_("contact")} | ||||||
|  | 								</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_organizations as o} | ||||||
|  | 								{#if Object.values(o) | ||||||
|  | 									.toString() | ||||||
|  | 									.toLowerCase() | ||||||
|  | 									.includes(searchvalue)} | ||||||
|  | 									<tr | ||||||
|  | 										class="odd:bg-white even:bg-gray-100" | ||||||
|  | 										data-rowid="org_{o.id}" | ||||||
|  | 									> | ||||||
|  | 										<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="text-sm font-medium text-gray-900"> | ||||||
|  | 													{o.name} | ||||||
|  | 												</div> | ||||||
|  | 											</div> | ||||||
|  | 										</td> | ||||||
|  | 										<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  | 											<div class="flex items-center"> | ||||||
|  | 												<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> | ||||||
|  | 										</td> | ||||||
|  | 										<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  | 											<div class="flex items-center"> | ||||||
|  | 												<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 border border-current" | ||||||
|  | 															>{o.contact.firstname} | ||||||
|  | 															{o.contact.middlename || ""} | ||||||
|  | 															{o.contact.lastname}</a | ||||||
|  | 														> | ||||||
|  | 													{:else}{$_("no-contact-specified")}{/if} | ||||||
|  | 												</div> | ||||||
|  | 											</div> | ||||||
|  | 										</td> | ||||||
|  | 										<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; | ||||||
|  | 														delete_modal_open = true; | ||||||
|  | 														delete_org = o; | ||||||
|  | 													}} | ||||||
|  | 													tabindex="0" | ||||||
|  | 													class="ml-4 text-red-600 hover:text-red-900 cursor-pointer" | ||||||
|  | 													>{$_("delete")}</button | ||||||
|  | 												> | ||||||
|  | 											{/if} | ||||||
|  | 										</td> | ||||||
|  | 									</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} | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes("ORGANIZATION:CREATE")} | {#if store.state.jwtinfo.userdetails.permissions.includes("ORGANIZATION:CREATE")} | ||||||
|   <AddOrgModal bind:current_organizations bind:modal_open /> | 	<AddOrgModal bind:current_organizations bind:modal_open /> | ||||||
|   <ImportRunnerModal | 	<ImportRunnerModal | ||||||
|     on:cancelDelete={(event) => { | 		on:cancelDelete={(event) => { | ||||||
|       import_modal_open = false; | 			import_modal_open = false; | ||||||
|     }} | 		}} | ||||||
|     passed_team={{}} | 		passed_team={{}} | ||||||
|     passed_org={{}} | 		passed_org={{}} | ||||||
|     passed_orgs={current_organizations} | 		passed_orgs={current_organizations} | ||||||
|     opened_from="OrgOverview" | 		opened_from="OrgOverview" | ||||||
|     current_runners={[]} | 		bind:import_modal_open | ||||||
|     bind:import_modal_open | 	/> | ||||||
|   /> |  | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
							
								
								
									
										151
									
								
								src/components/pdf_generation/DocumentServer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/components/pdf_generation/DocumentServer.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | |||||||
|  | class DocumentServer { | ||||||
|  |   baseUrl: string; | ||||||
|  |   apiKey: string; | ||||||
|  |  | ||||||
|  |   constructor(baseUrl: string, apiKey: string) { | ||||||
|  |     this.baseUrl = baseUrl; | ||||||
|  |     this.apiKey = apiKey; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async generateCards(cards: any[], locale: string) { | ||||||
|  |     const generateCards = new Array<any>(); | ||||||
|  |  | ||||||
|  |     for (let i = 0; i < cards.length; i++) { | ||||||
|  |       const card = { | ||||||
|  |         id: cards[i].id, | ||||||
|  |         enabled: cards[i].enabled, | ||||||
|  |         code: cards[i].code, | ||||||
|  |         runner: { | ||||||
|  |           id: cards[i]?.runner?.id, | ||||||
|  |           first_name: cards[i]?.runner?.firstname, | ||||||
|  |           middle_name: cards[i]?.runner?.middlename, | ||||||
|  |           last_name: cards[i]?.runner?.lastname, | ||||||
|  |           group: { | ||||||
|  |             id: cards[i]?.runner?.group.id, | ||||||
|  |             name: cards[i]?.runner?.group.name, | ||||||
|  |             parent_group: { | ||||||
|  |               id: cards[i]?.runner?.group?.parentGroup?.id, | ||||||
|  |               name: cards[i]?.runner?.group?.parentGroup?.name, | ||||||
|  |             }, | ||||||
|  |           }, | ||||||
|  |         }, | ||||||
|  |       }; | ||||||
|  |       generateCards.push(card); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const response = await fetch( | ||||||
|  |       `${this.baseUrl}/v1/pdfs/cards?key=${this.apiKey}`, | ||||||
|  |       { | ||||||
|  |         method: "POST", | ||||||
|  |         headers: { | ||||||
|  |           "Content-Type": "application/json", | ||||||
|  |         }, | ||||||
|  |         body: JSON.stringify({ | ||||||
|  |           locale, | ||||||
|  |           cards: generateCards, | ||||||
|  |         }), | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     const blob = await response.blob(); | ||||||
|  |     return blob; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async generateContracts(runners: any[], locale: string) { | ||||||
|  |     const generateRunners = new Array<any>(); | ||||||
|  |  | ||||||
|  |     for (let i = 0; i < runners.length; i++) { | ||||||
|  |       console.log(runners[i]); | ||||||
|  |       const card = { | ||||||
|  |         id: runners[i].id, | ||||||
|  |         first_name: runners[i].firstname, | ||||||
|  |         middle_name: runners[i].middlename, | ||||||
|  |         last_name: runners[i].lastname, | ||||||
|  |         group: { | ||||||
|  |           id: runners[i].group.id, | ||||||
|  |           name: runners[i].group.name, | ||||||
|  |           parent_group: { | ||||||
|  |             id: runners[i]?.group?.parentGroup?.id, | ||||||
|  |             name: runners[i]?.group?.parentGroup?.name, | ||||||
|  |           }, | ||||||
|  |         }, | ||||||
|  |       }; | ||||||
|  |       generateRunners.push(card); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const response = await fetch( | ||||||
|  |       `${this.baseUrl}/v1/pdfs/contracts?key=${this.apiKey}`, | ||||||
|  |       { | ||||||
|  |         method: "POST", | ||||||
|  |         headers: { | ||||||
|  |           "Content-Type": "application/json", | ||||||
|  |         }, | ||||||
|  |         body: JSON.stringify({ | ||||||
|  |           locale, | ||||||
|  |           runners: generateRunners, | ||||||
|  |         }), | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     const blob = await response.blob(); | ||||||
|  |     return blob; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async generateCertificates(runners: any[], locale: string) { | ||||||
|  |     const generateRunners = new Array<any>(); | ||||||
|  |  | ||||||
|  |     for (let i = 0; i < runners.length; i++) { | ||||||
|  |       const certificate = { | ||||||
|  |         id: runners[i].id, | ||||||
|  |         first_name: runners[i].firstname, | ||||||
|  |         middle_name: runners[i].middlename, | ||||||
|  |         last_name: runners[i].lastname, | ||||||
|  |         self_service_link: runners[i].selfserviceLink, | ||||||
|  |         group: { | ||||||
|  |           id: runners[i].group.id, | ||||||
|  |           name: runners[i].group.name, | ||||||
|  |           parent_group: { | ||||||
|  |             id: runners[i]?.group?.parentGroup?.id, | ||||||
|  |             name: runners[i]?.group?.parentGroup?.name, | ||||||
|  |           }, | ||||||
|  |         }, | ||||||
|  |         distance: runners[i].distance, | ||||||
|  |         distance_donations: runners[i].distanceDonations.map( | ||||||
|  |           (distanceDonation: any) => { | ||||||
|  |             return { | ||||||
|  |               id: distanceDonation.id, | ||||||
|  |               amount: distanceDonation.amount, | ||||||
|  |               amount_per_distance: distanceDonation.amountPerDistance, | ||||||
|  |               donor: { | ||||||
|  |                 id: distanceDonation.donor.id, | ||||||
|  |                 first_name: distanceDonation.donor.firstname, | ||||||
|  |                 middle_name: distanceDonation.donor.middlename, | ||||||
|  |                 last_name: distanceDonation.donor.lastname, | ||||||
|  |               }, | ||||||
|  |             }; | ||||||
|  |           }, | ||||||
|  |         ), | ||||||
|  |       }; | ||||||
|  |       generateRunners.push(certificate); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const response = await fetch( | ||||||
|  |       `${this.baseUrl}/v1/pdfs/certificates?key=${this.apiKey}`, | ||||||
|  |       { | ||||||
|  |         method: "POST", | ||||||
|  |         headers: { | ||||||
|  |           "Content-Type": "application/json", | ||||||
|  |         }, | ||||||
|  |         body: JSON.stringify({ | ||||||
|  |           locale, | ||||||
|  |           runners: generateRunners, | ||||||
|  |         }), | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     const blob = await response.blob(); | ||||||
|  |     return blob; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default DocumentServer; | ||||||
							
								
								
									
										81
									
								
								src/components/pdf_generation/DownloadProgressModal.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/components/pdf_generation/DownloadProgressModal.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | <script> | ||||||
|  | 	import { _ } from "svelte-i18n"; | ||||||
|  | 	import { clickOutside } from "../base/outsideclick"; | ||||||
|  | 	import { onMount } from "svelte"; | ||||||
|  | 	export let download_details = ""; | ||||||
|  | 	export let modal_open; | ||||||
|  | 	onMount(() => { | ||||||
|  | 		document.onkeydown = (e) => { | ||||||
|  | 			e = e || window.event; | ||||||
|  | 			if (e.key === "Escape") { | ||||||
|  | 				modal_open = false; | ||||||
|  | 			} | ||||||
|  | 			if (e.keyCode === 13) { | ||||||
|  | 				if (createbtnenabled === true) { | ||||||
|  | 					createbtnenabled = false; | ||||||
|  | 					submit(); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		}; | ||||||
|  | 	}); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | {#if modal_open} | ||||||
|  | 	<div | ||||||
|  | 		class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|  | 		use:clickOutside | ||||||
|  | 		on:click_outside={() => { | ||||||
|  | 			modal_open = false; | ||||||
|  | 		}} | ||||||
|  | 	> | ||||||
|  | 		<div | ||||||
|  | 			class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|  | 		> | ||||||
|  | 			<div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|  | 				<div | ||||||
|  | 					class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|  | 					data-id="modal_backdrop" | ||||||
|  | 				/> | ||||||
|  | 			</div> | ||||||
|  | 			<span | ||||||
|  | 				class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|  | 				aria-hidden="true">​</span | ||||||
|  | 			> | ||||||
|  | 			<div | ||||||
|  | 				class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|  | 				role="dialog" | ||||||
|  | 				aria-modal="true" | ||||||
|  | 				aria-labelledby="modal-headline" | ||||||
|  | 			> | ||||||
|  | 				<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|  | 					<div class=""> | ||||||
|  | 						<div | ||||||
|  | 							class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|  | 						> | ||||||
|  | 							<svg | ||||||
|  | 								xmlns="http://www.w3.org/2000/svg" | ||||||
|  | 								viewBox="0 0 24 24" | ||||||
|  | 								class="h-6 w-6 text-blue-600" | ||||||
|  | 								fill="currentColor" | ||||||
|  | 								width="24" | ||||||
|  | 								height="24" | ||||||
|  | 								><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|  | 								<path | ||||||
|  | 									d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z" | ||||||
|  | 								/></svg | ||||||
|  | 							> | ||||||
|  | 						</div> | ||||||
|  | 						<div class="mt-3 sm:text-left text-base"> | ||||||
|  | 							<h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|  | 								{$_('download_laeuft')} | ||||||
|  | 							</h3> | ||||||
|  | 							<div class="w-full"> | ||||||
|  | 								{download_details} | ||||||
|  | 							</div> | ||||||
|  | 						</div> | ||||||
|  | 					</div> | ||||||
|  | 				</div> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
|  | 	</div> | ||||||
|  | {/if} | ||||||
| @@ -1,364 +1,197 @@ | |||||||
| <script> | <script> | ||||||
|   import { getLocaleFromNavigator, _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import { | 	import { | ||||||
|     RunnerCardService, | 		RunnerCardService, | ||||||
|     RunnerOrganizationService, | 		RunnerOrganizationService, | ||||||
|     RunnerTeamService, | 		RunnerTeamService, | ||||||
|   } from "@odit/lfk-client-js"; | 	} from "@odit/lfk-client-js"; | ||||||
|  | 	import toast from "svelte-french-toast"; | ||||||
|  | 	import DocumentServer from "./DocumentServer.ts"; | ||||||
|  |  | ||||||
|   import { init } from "@paralleldrive/cuid2"; | 	import { init } from "@paralleldrive/cuid2"; | ||||||
|   const createId = init({ length: 10, fingerprint: "lfk-frontend" }); | 	const createId = init({ length: 10, fingerprint: "lfk-frontend" }); | ||||||
|  | 	const documentServer = new DocumentServer( | ||||||
|  | 		config.baseurl_documentserver, | ||||||
|  | 		config.documentserver_key | ||||||
|  | 	); | ||||||
|  |  | ||||||
|   export let cards_show = false; | 	export let cards_show = false; | ||||||
|   export let generate_cards = []; | 	export let generate_cards = []; | ||||||
|   export let generate_runners = []; | 	export let generate_runners = []; | ||||||
|   export let generate_orgs = []; | 	export let generate_orgs = []; | ||||||
|   export let generate_teams = []; | 	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) { | 	function download(blob, fileName) { | ||||||
|     cards_dropdown_open = false; | 		const url = window.URL.createObjectURL(blob); | ||||||
|  | 		let a = document.createElement("a"); | ||||||
|  | 		a.href = url; | ||||||
|  | 		a.download = fileName; | ||||||
|  | 		document.body.appendChild(a); | ||||||
|  | 		a.click(); | ||||||
|  | 		a.remove(); | ||||||
|  | 		toast.dismiss(); | ||||||
|  | 		toast.success($_("pdf-successfully-generated")); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|     if (generate_orgs.length > 0) { | 	function generateRunnerCards(locale) { | ||||||
|       generateOrgCards(locale); | 		if (generate_orgs.length > 0) { | ||||||
|     } else if (generate_teams.length > 0) { | 			generateOrgCards(locale); | ||||||
|       generateTeamCards(locale); | 		} else if (generate_teams.length > 0) { | ||||||
|     } else if (generate_runners.length > 0) { | 			generateTeamCards(locale); | ||||||
|       generateRunnersCards(locale); | 		} else if (generate_runners.length > 0) { | ||||||
|     } else { | 			generateRunnersCards(locale); | ||||||
|       generateCards(locale); | 		} else { | ||||||
|     } | 			generateCards(locale); | ||||||
|   } | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|   function generateCards(locale) { | 	function generateCards(locale) { | ||||||
|     toast.loading($_("generating-pdf")); | 		toast.loading($_("generating-pdf")); | ||||||
|     fetch( | 		documentServer | ||||||
|       `${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`, | 			.generateCards(generate_cards, locale) | ||||||
|       { | 			.then((blob) => { | ||||||
|         method: "POST", | 				download(blob, `${$_("runnercards")}-${locale}-${createId()}.pdf`); | ||||||
|         headers: { | 			}) | ||||||
|           "Content-Type": "application/json", | 			.catch((err) => { | ||||||
|         }, | 				console.error(err); | ||||||
|         body: JSON.stringify(generate_cards), | 			}); | ||||||
|       } | 	} | ||||||
|     ) |  | ||||||
|       .then((response) => { |  | ||||||
|         if (response.status != "200") { |  | ||||||
|           toast.dismiss(); |  | ||||||
|           toast.error($_("pdf-generation-failed")); |  | ||||||
|         } else { |  | ||||||
|           return response.blob(); |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|       .then((blob) => { |  | ||||||
|         const url = window.URL.createObjectURL(blob); |  | ||||||
|         let a = document.createElement("a"); |  | ||||||
|         a.href = url; |  | ||||||
|         a.download = `${$_("runnercards")}-${locale}-${createId()}.pdf`; |  | ||||||
|         document.body.appendChild(a); |  | ||||||
|         a.click(); |  | ||||||
|         a.remove(); |  | ||||||
|         toast.dismiss(); |  | ||||||
|         toast($_("pdf-successfully-generated")); |  | ||||||
|       }) |  | ||||||
|       .catch((err) => { |  | ||||||
|         console.error(err); |  | ||||||
|       }); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   async function generateRunnersCards(locale) { | 	async function generateRunnersCards(locale) { | ||||||
|     toast.loading($_("generating-pdf")); | 		toast.loading($_("generating-pdf")); | ||||||
|     const current_cards = await RunnerCardService.runnerCardControllerGetAll(); | 		const current_cards = await RunnerCardService.runnerCardControllerGetAll(); | ||||||
|     let cards = []; | 		let cards = []; | ||||||
|     for (let runner of generate_runners) { | 		for (let runner of generate_runners) { | ||||||
|       let card = current_cards.find((c) => c.runner?.id == runner.id); | 			let card = current_cards.find((c) => c.runner?.id == runner.id); | ||||||
|       if (!card) { | 			if (!card) { | ||||||
|         card = await RunnerCardService.runnerCardControllerPost({ | 				card = await RunnerCardService.runnerCardControllerPost({ | ||||||
|           runner: runner.id, | 					runner: runner.id, | ||||||
|         }); | 				}); | ||||||
|       } | 			} | ||||||
|       cards.push(card); | 			cards.push(card); | ||||||
|     } | 		} | ||||||
|     fetch( | 		documentServer | ||||||
|       `${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`, | 			.generateCards(cards, locale) | ||||||
|       { | 			.then((blob) => { | ||||||
|         method: "POST", | 				let fileName = `${$_("runnercards")}-${locale}-${createId()}.pdf`; | ||||||
|         headers: { | 				if (generate_runners.length == 1) { | ||||||
|           "Content-Type": "application/json", | 					fileName = `${$_("runnercards")}_${generate_runners[0].firstname}_${ | ||||||
|         }, | 						generate_runners[0].lastname | ||||||
|         body: JSON.stringify(cards), | 					}-${locale}-${createId()}.pdf`; | ||||||
|       } | 				} | ||||||
|     ) | 				download(blob, fileName); | ||||||
|       .then((response) => { | 			}) | ||||||
|         if (response.status != "200") { | 			.catch((err) => {}); | ||||||
|           toast.dismiss(); | 	} | ||||||
|           toast.error($_("pdf-generation-failed")); |  | ||||||
|         } else { |  | ||||||
|           return response.blob(); |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|       .then((blob) => { |  | ||||||
|         const url = window.URL.createObjectURL(blob); |  | ||||||
|         let a = document.createElement("a"); |  | ||||||
|         a.href = url; |  | ||||||
|         if (generate_runners.length == 1) { |  | ||||||
|           a.download = `${$_("runnercards")}_${generate_runners[0].firstname}_${ |  | ||||||
|             generate_runners[0].lastname |  | ||||||
|           }-${locale}-${createId()}.pdf`; |  | ||||||
|         } else { |  | ||||||
|           a.download = `${$_("runnercards")}-${locale}-${createId()}.pdf`; |  | ||||||
|         } |  | ||||||
|         document.body.appendChild(a); |  | ||||||
|         a.click(); |  | ||||||
|         a.remove(); |  | ||||||
|         toast.dismiss(); |  | ||||||
|         toast($_("pdf-successfully-generated")); |  | ||||||
|       }) |  | ||||||
|       .catch((err) => {}); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   async function generateTeamCards(locale) { | 	async function generateTeamCards(locale) { | ||||||
|     toast.loading($_("generating-pdfs")); | 		toast.loading($_("generating-pdfs")); | ||||||
|     let count = 0; | 		let count = 0; | ||||||
|     const current_cards = await RunnerCardService.runnerCardControllerGetAll(); | 		const current_cards = await RunnerCardService.runnerCardControllerGetAll(); | ||||||
|     for (const t of generate_teams) { | 		for (const t of generate_teams) { | ||||||
|       const runners = await RunnerTeamService.runnerTeamControllerGetRunners( | 			const runners = await RunnerTeamService.runnerTeamControllerGetRunners( | ||||||
|         t.id | 				t.id | ||||||
|       ); | 			); | ||||||
|       let cards = []; | 			let cards = []; | ||||||
|       for (let runner of runners) { | 			for (let runner of runners) { | ||||||
|         let card = current_cards.find((c) => c.runner?.id == runner.id); | 				let card = current_cards.find((c) => c.runner?.id == runner.id); | ||||||
|         if (!card) { | 				if (!card) { | ||||||
|           card = await RunnerCardService.runnerCardControllerPost({ | 					card = await RunnerCardService.runnerCardControllerPost({ | ||||||
|             runner: runner.id, | 						runner: runner.id, | ||||||
|           }); | 					}); | ||||||
|         } | 				} | ||||||
|         cards.push(card); | 				cards.push(card); | ||||||
|       } | 			} | ||||||
|       fetch( | 			documentServer | ||||||
|         `${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`, | 				.generateCards(cards, locale) | ||||||
|         { | 				.then((blob) => { | ||||||
|           method: "POST", | 					download( | ||||||
|           headers: { | 						blob, | ||||||
|             "Content-Type": "application/json", | 						`${$_("runnercards")}_${t.name}-${locale}-${createId()}.pdf` | ||||||
|           }, | 					); | ||||||
|           body: JSON.stringify(cards), | 				}) | ||||||
|         } | 				.catch((err) => {}); | ||||||
|       ) | 		} | ||||||
|         .then((response) => { | 	} | ||||||
|           if (response.status != "200") { |  | ||||||
|             toast.dismiss(); |  | ||||||
|             toast.error($_("pdf-generation-failed")); |  | ||||||
|           } else { |  | ||||||
|             return response.blob(); |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|         .then((blob) => { |  | ||||||
|           count++; |  | ||||||
|           const url = window.URL.createObjectURL(blob); |  | ||||||
|           let a = document.createElement("a"); |  | ||||||
|           a.href = url; |  | ||||||
|           a.download = `${$_("runnercards")}_${ |  | ||||||
|             t.name |  | ||||||
|           }-${locale}-${createId()}.pdf`; |  | ||||||
|           document.body.appendChild(a); |  | ||||||
|           a.click(); |  | ||||||
|           a.remove(); |  | ||||||
|           if (count === generate_teams.length) { |  | ||||||
|             toast.dismiss(); |  | ||||||
|             toast.success($_("pdfs-successfully-generated")); |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|         .catch((err) => {}); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   async function generateOrgCards(locale) { | 	async function generateOrgCards(locale) { | ||||||
|     toast.loading($_("generating-pdfs")); | 		toast.loading($_("generating-pdfs")); | ||||||
|     const current_cards = await RunnerCardService.runnerCardControllerGetAll(); | 		const current_cards = await RunnerCardService.runnerCardControllerGetAll(); | ||||||
|     let count = 0; | 		let count = 0; | ||||||
|     let count_orgs = 0; | 		let count_orgs = 0; | ||||||
|     for (const o of generate_orgs) { | 		for (const o of generate_orgs) { | ||||||
|       count_orgs++; | 			count_orgs++; | ||||||
|       let count = 0; | 			let count = 0; | ||||||
|       let runners = | 			let runners = | ||||||
|         await RunnerOrganizationService.runnerOrganizationControllerGetRunners( | 				await RunnerOrganizationService.runnerOrganizationControllerGetRunners( | ||||||
|           o.id, | 					o.id, | ||||||
|           true | 					true | ||||||
|         ); | 				); | ||||||
|       let cards = []; | 			let cards = []; | ||||||
|       for (let runner of runners) { | 			for (let runner of runners) { | ||||||
|         let card = current_cards.find((c) => c.runner?.id == runner.id); | 				let card = current_cards.find((c) => c.runner?.id == runner.id); | ||||||
|         if (!card) { | 				if (!card) { | ||||||
|           card = await RunnerCardService.runnerCardControllerPost({ | 					card = await RunnerCardService.runnerCardControllerPost({ | ||||||
|             runner: runner.id, | 						runner: runner.id, | ||||||
|           }); | 					}); | ||||||
|         } | 				} | ||||||
|         cards.push(card); | 				cards.push(card); | ||||||
|       } | 			} | ||||||
|       await fetch( | 			await documentServer | ||||||
|         `${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`, | 				.generateCards(cards, locale) | ||||||
|         { | 				.then((blob) => { | ||||||
|           method: "POST", | 					download( | ||||||
|           headers: { | 						blob, | ||||||
|             "Content-Type": "application/json", | 						`${$_("runnercards")}_${o.name}_direct-${locale}-${createId()}.pdf` | ||||||
|           }, | 					); | ||||||
|           body: JSON.stringify(cards), | 				}) | ||||||
|         } | 				.catch((err) => {}); | ||||||
|       ) | 			for (const t of o.teams) { | ||||||
|         .then((response) => { | 				count++; | ||||||
|           if (response.status != "200") { | 				let runners = await RunnerTeamService.runnerTeamControllerGetRunners( | ||||||
|             toast.dismiss(); | 					t.id | ||||||
|             toast.error($_("pdf-generation-failed")); | 				); | ||||||
|           } else { | 				let cards = []; | ||||||
|             return response.blob(); | 				for (let runner of runners) { | ||||||
|           } | 					let card = current_cards.find((c) => c.runner?.id == runner.id); | ||||||
|         }) | 					if (!card) { | ||||||
|         .then((blob) => { | 						card = await RunnerCardService.runnerCardControllerPost({ | ||||||
|           const url = window.URL.createObjectURL(blob); | 							runner: runner.id, | ||||||
|           let a = document.createElement("a"); | 						}); | ||||||
|           a.href = url; | 					} | ||||||
|           a.download = `${$_("runnercards")}_${ | 					cards.push(card); | ||||||
|             o.name | 				} | ||||||
|           }_direct-${locale}-${createId()}.pdf`; | 				await documentServer | ||||||
|           document.body.appendChild(a); | 					.generateCards(cards, locale) | ||||||
|           a.click(); | 					.then((blob) => { | ||||||
|           a.remove(); | 						download( | ||||||
|           if (count === o.teams.length && count_orgs === generate_orgs.length) { | 							blob, | ||||||
|             toast.dismiss(); | 							`${$_("runnercards")}_${o.name}_${ | ||||||
|             toast.success($_("pdfs-successfully-generated")); | 								t.name | ||||||
|           } | 							}-${locale}-${createId()}.pdf` | ||||||
|         }) | 						); | ||||||
|         .catch((err) => {}); | 					}) | ||||||
|       for (const t of o.teams) { | 					.catch((err) => {}); | ||||||
|         count++; | 			} | ||||||
|         let runners = await RunnerTeamService.runnerTeamControllerGetRunners( | 		} | ||||||
|           t.id | 	} | ||||||
|         ); |  | ||||||
|         let cards = []; |  | ||||||
|         for (let runner of runners) { |  | ||||||
|           let card = current_cards.find((c) => c.runner?.id == runner.id); |  | ||||||
|           if (!card) { |  | ||||||
|             card = await RunnerCardService.runnerCardControllerPost({ |  | ||||||
|               runner: runner.id, |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|           cards.push(card); |  | ||||||
|         } |  | ||||||
|         await fetch( |  | ||||||
|           `${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`, |  | ||||||
|           { |  | ||||||
|             method: "POST", |  | ||||||
|             headers: { |  | ||||||
|               "Content-Type": "application/json", |  | ||||||
|             }, |  | ||||||
|             body: JSON.stringify(cards), |  | ||||||
|           } |  | ||||||
|         ) |  | ||||||
|           .then((response) => { |  | ||||||
|             if (response.status != "200") { |  | ||||||
|               toast.dismiss(); |  | ||||||
|               toast.error($_("pdf-generation-failed")); |  | ||||||
|             } else { |  | ||||||
|               return response.blob(); |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|           .then((blob) => { |  | ||||||
|             const url = window.URL.createObjectURL(blob); |  | ||||||
|             let a = document.createElement("a"); |  | ||||||
|             a.href = url; |  | ||||||
|             a.download = `${$_("runnercards")}_${o.name}_${ |  | ||||||
|               t.name |  | ||||||
|             }-${locale}-${createId()}.pdf`; |  | ||||||
|             document.body.appendChild(a); |  | ||||||
|             a.click(); |  | ||||||
|             a.remove(); |  | ||||||
|             if ( |  | ||||||
|               count === o.teams.length && |  | ||||||
|               count_orgs === generate_orgs.length |  | ||||||
|             ) { |  | ||||||
|               toast.dismiss(); |  | ||||||
|               toast($_("pdfs-successfully-generated")); |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|           .catch((err) => {}); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if cards_show} | {#if cards_show} | ||||||
|   <div id="cards:dropdown" class="relative inline-block"> | 	<button | ||||||
|     <div> | 		on:click={() => { | ||||||
|       <button | 			generateRunnerCards("de"); | ||||||
|         on:click={() => { | 		}} | ||||||
|           cards_dropdown_open = !cards_dropdown_open; | 		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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|         }} | 	> | ||||||
|         type="button" | 		{$_("generate-runnercards")}: DE | ||||||
|         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" | 	</button> | ||||||
|         id="options-menu" | 	<button | ||||||
|         aria-haspopup="true" | 		on:click={() => { | ||||||
|         aria-expanded="true" | 			generateRunnerCards("en"); | ||||||
|       > | 		}} | ||||||
|         {$_("generate-runnercards")} | 		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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|         <svg | 	> | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 		{$_("generate-runnercards")}: EN | ||||||
|           width="24" | 	</button> | ||||||
|           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 z-10" |  | ||||||
|         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} | {/if} | ||||||
|   | |||||||
| @@ -4,28 +4,23 @@ | |||||||
|     DonationService, |     DonationService, | ||||||
|     RunnerTeamService, |     RunnerTeamService, | ||||||
|     RunnerOrganizationService, |     RunnerOrganizationService, | ||||||
|  | 	RunnerService | ||||||
|   } from "@odit/lfk-client-js"; |   } from "@odit/lfk-client-js"; | ||||||
|  |  | ||||||
|   import { init } from "@paralleldrive/cuid2"; |   import { init } from "@paralleldrive/cuid2"; | ||||||
|  |   import toast from "svelte-french-toast"; | ||||||
|  |   import DocumentServer from "./DocumentServer"; | ||||||
|   const createId = init({ length: 10, fingerprint: "lfk-frontend" }); |   const createId = init({ length: 10, fingerprint: "lfk-frontend" }); | ||||||
|  |   const documentServer = new DocumentServer( | ||||||
|  |     config.baseurl_documentserver, | ||||||
|  |     config.documentserver_key | ||||||
|  |   ); | ||||||
|  |  | ||||||
|   export let certificates_show = false; |   export let certificates_show = false; | ||||||
|   export let generate_runners = []; |   export let generate_runners = []; | ||||||
|   export let generate_orgs = []; |   export let generate_orgs = []; | ||||||
|   export let generate_teams = []; |   export let generate_teams = []; | ||||||
|   $: certificates_dropdown_open = false; |  | ||||||
|   document.addEventListener("click", function (e) { |  | ||||||
|     if ( |  | ||||||
|       e.target.parentNode?.parentNode?.id != "certificates:dropdown" && |  | ||||||
|       e.target.parentNode?.parentNode?.id != "certificates:dropdown:menu" |  | ||||||
|     ) { |  | ||||||
|       certificates_dropdown_open = false; |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   function generateCertificates(locale) { |   function generateCertificates(locale) { | ||||||
|     certificates_dropdown_open = false; |  | ||||||
|  |  | ||||||
|     if (generate_orgs.length > 0) { |     if (generate_orgs.length > 0) { | ||||||
|       generateOrgCertificates(locale); |       generateOrgCertificates(locale); | ||||||
|     } else if (generate_teams.length > 0) { |     } else if (generate_teams.length > 0) { | ||||||
| @@ -34,6 +29,17 @@ | |||||||
|       generateRunnerCertificates(locale); |       generateRunnerCertificates(locale); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |   function download(blob, fileName) { | ||||||
|  |     const url = window.URL.createObjectURL(blob); | ||||||
|  |     let a = document.createElement("a"); | ||||||
|  |     a.href = url; | ||||||
|  |     a.download = fileName; | ||||||
|  |     document.body.appendChild(a); | ||||||
|  |     a.click(); | ||||||
|  |     a.remove(); | ||||||
|  |     toast.dismiss(); | ||||||
|  |     toast.success($_("pdf-successfully-generated")); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   async function generateRunnerCertificates(locale) { |   async function generateRunnerCertificates(locale) { | ||||||
|     toast.loading($_("generating-pdf")); |     toast.loading($_("generating-pdf")); | ||||||
| @@ -41,44 +47,21 @@ | |||||||
|       (await DonationService.donationControllerGetAll()) || []; |       (await DonationService.donationControllerGetAll()) || []; | ||||||
|     let certificateRunners = []; |     let certificateRunners = []; | ||||||
|     for (let runner of generate_runners) { |     for (let runner of generate_runners) { | ||||||
|       runner.distanceDonations = | 	  const linkRunner = await RunnerService.runnerControllerGetOne(runner.id) | ||||||
|  |       linkRunner.distanceDonations = | ||||||
|         current_donations.filter((d) => d.runner?.id == runner.id) || []; |         current_donations.filter((d) => d.runner?.id == runner.id) || []; | ||||||
|       certificateRunners.push(runner); |       certificateRunners.push(linkRunner); | ||||||
|     } |     } | ||||||
|     fetch( |     documentServer | ||||||
|       `${config.baseurl_documentserver}/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`, |       .generateCertificates(certificateRunners, locale) | ||||||
|       { |  | ||||||
|         method: "POST", |  | ||||||
|         headers: { |  | ||||||
|           "Content-Type": "application/json", |  | ||||||
|         }, |  | ||||||
|         body: JSON.stringify(certificateRunners), |  | ||||||
|       } |  | ||||||
|     ) |  | ||||||
|       .then((response) => { |  | ||||||
|         if (response.status != "200") { |  | ||||||
|           toast.dismiss(); |  | ||||||
|           toast.error($_("pdf-generation-failed")); |  | ||||||
|         } else { |  | ||||||
|           return response.blob(); |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|       .then((blob) => { |       .then((blob) => { | ||||||
|         const url = window.URL.createObjectURL(blob); |         let fileName = `${$_("certificates")}-${locale}.pdf`; | ||||||
|         let a = document.createElement("a"); |  | ||||||
|         a.href = url; |  | ||||||
|         if (generate_runners.length == 1) { |         if (generate_runners.length == 1) { | ||||||
|           a.download = `${$_("certificates")}_${ |           fileName = `${$_("certificates")}_${ | ||||||
|             generate_runners[0].firstname |             generate_runners[0].firstname | ||||||
|           }_${generate_runners[0].lastname}-${locale}-${createId()}.pdf`; |           }_${generate_runners[0].lastname}-${locale}-${createId()}.pdf`; | ||||||
|         } else { |  | ||||||
|           a.download = `${$_("certificates")}-${locale}.pdf`; |  | ||||||
|         } |         } | ||||||
|         document.body.appendChild(a); |         download(blob, fileName); | ||||||
|         a.click(); |  | ||||||
|         a.remove(); |  | ||||||
|         toast.dismiss(); |  | ||||||
|         toast($_("pdf-successfully-generated")); |  | ||||||
|       }) |       }) | ||||||
|       .catch((err) => {}); |       .catch((err) => {}); | ||||||
|   } |   } | ||||||
| @@ -90,7 +73,8 @@ | |||||||
|       (await DonationService.donationControllerGetAll()) || []; |       (await DonationService.donationControllerGetAll()) || []; | ||||||
|     for (const t of generate_teams) { |     for (const t of generate_teams) { | ||||||
|       const runners = await RunnerTeamService.runnerTeamControllerGetRunners( |       const runners = await RunnerTeamService.runnerTeamControllerGetRunners( | ||||||
|         t.id |         t.id, | ||||||
|  |         true | ||||||
|       ); |       ); | ||||||
|       let certificateRunners = []; |       let certificateRunners = []; | ||||||
|       for (let runner of runners) { |       for (let runner of runners) { | ||||||
| @@ -98,39 +82,14 @@ | |||||||
|           current_donations.filter((d) => d.runner?.id == runner.id) || []; |           current_donations.filter((d) => d.runner?.id == runner.id) || []; | ||||||
|         certificateRunners.push(runner); |         certificateRunners.push(runner); | ||||||
|       } |       } | ||||||
|       fetch( |       documentServer | ||||||
|         `${config.baseurl_documentserver}/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`, |         .generateCertificates(certificateRunners, locale) | ||||||
|         { |  | ||||||
|           method: "POST", |  | ||||||
|           headers: { |  | ||||||
|             "Content-Type": "application/json", |  | ||||||
|           }, |  | ||||||
|           body: JSON.stringify(certificateRunners), |  | ||||||
|         } |  | ||||||
|       ) |  | ||||||
|         .then((response) => { |  | ||||||
|           if (response.status != "200") { |  | ||||||
|             toast.dismiss(); |  | ||||||
|             toast.error($_("pdf-generation-failed")); |  | ||||||
|           } else { |  | ||||||
|             return response.blob(); |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|         .then((blob) => { |         .then((blob) => { | ||||||
|           count++; |           count++; | ||||||
|           const url = window.URL.createObjectURL(blob); |           download( | ||||||
|           let a = document.createElement("a"); |             blob, | ||||||
|           a.href = url; |             `${$_("certificates")}_${t.name}-${locale}-${createId()}.pdf` | ||||||
|           a.download = `${$_("certificates")}_${ |           ); | ||||||
|             t.name |  | ||||||
|           }-${locale}-${createId()}.pdf`; |  | ||||||
|           document.body.appendChild(a); |  | ||||||
|           a.click(); |  | ||||||
|           a.remove(); |  | ||||||
|           if (count === generate_teams.length) { |  | ||||||
|             toast.dismiss(); |  | ||||||
|             toast.success($_("pdfs-successfully-generated")); |  | ||||||
|           } |  | ||||||
|         }) |         }) | ||||||
|         .catch((err) => {}); |         .catch((err) => {}); | ||||||
|     } |     } | ||||||
| @@ -148,7 +107,8 @@ | |||||||
|       let runners = |       let runners = | ||||||
|         await RunnerOrganizationService.runnerOrganizationControllerGetRunners( |         await RunnerOrganizationService.runnerOrganizationControllerGetRunners( | ||||||
|           o.id, |           o.id, | ||||||
|           true |           true, | ||||||
|  | 		  true | ||||||
|         ); |         ); | ||||||
|       let certificateRunners = []; |       let certificateRunners = []; | ||||||
|       for (let runner of runners) { |       for (let runner of runners) { | ||||||
| @@ -156,44 +116,20 @@ | |||||||
|           current_donations.filter((d) => d.runner?.id == runner.id) || []; |           current_donations.filter((d) => d.runner?.id == runner.id) || []; | ||||||
|         certificateRunners.push(runner); |         certificateRunners.push(runner); | ||||||
|       } |       } | ||||||
|       await fetch( |       await documentServer | ||||||
|         `${config.baseurl_documentserver}/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`, |         .generateCertificates(certificateRunners, locale) | ||||||
|         { |  | ||||||
|           method: "POST", |  | ||||||
|           headers: { |  | ||||||
|             "Content-Type": "application/json", |  | ||||||
|           }, |  | ||||||
|           body: JSON.stringify(certificateRunners), |  | ||||||
|         } |  | ||||||
|       ) |  | ||||||
|         .then((response) => { |  | ||||||
|           if (response.status != "200") { |  | ||||||
|             toast.dismiss(); |  | ||||||
|             toast.error($_("pdf-generation-failed")); |  | ||||||
|           } else { |  | ||||||
|             return response.blob(); |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|         .then((blob) => { |         .then((blob) => { | ||||||
|           const url = window.URL.createObjectURL(blob); |           download( | ||||||
|           let a = document.createElement("a"); |             blob, | ||||||
|           a.href = url; |             `${$_("certificates")}_${o.name}-${locale}-${createId()}.pdf` | ||||||
|           a.download = `${$_("certificates")}_${ |           ); | ||||||
|             o.name |  | ||||||
|           }-${locale}-${createId()}.pdf`; |  | ||||||
|           document.body.appendChild(a); |  | ||||||
|           a.click(); |  | ||||||
|           a.remove(); |  | ||||||
|           if (count === o.teams.length && count_orgs === generate_orgs.length) { |  | ||||||
|             toast.dismiss(); |  | ||||||
|             toast.success($_("pdfs-successfully-generated")); |  | ||||||
|           } |  | ||||||
|         }) |         }) | ||||||
|         .catch((err) => {}); |         .catch((err) => {}); | ||||||
|       for (const t of o.teams) { |       for (const t of o.teams) { | ||||||
|         count++; |         count++; | ||||||
|         let runners = await RunnerTeamService.runnerTeamControllerGetRunners( |         let runners = await RunnerTeamService.runnerTeamControllerGetRunners( | ||||||
|           t.id |           t.id, | ||||||
|  | 		  true | ||||||
|         ); |         ); | ||||||
|         let certificateRunners = []; |         let certificateRunners = []; | ||||||
|         for (let runner of runners) { |         for (let runner of runners) { | ||||||
| @@ -201,40 +137,21 @@ | |||||||
|             current_donations.filter((d) => d.runner?.id == runner.id) || []; |             current_donations.filter((d) => d.runner?.id == runner.id) || []; | ||||||
|           certificateRunners.push(runner); |           certificateRunners.push(runner); | ||||||
|         } |         } | ||||||
|         await fetch( |         await documentServer | ||||||
|           `${config.baseurl_documentserver}/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`, |           .generateCertificates(certificateRunners, locale) | ||||||
|           { |  | ||||||
|             method: "POST", |  | ||||||
|             headers: { |  | ||||||
|               "Content-Type": "application/json", |  | ||||||
|             }, |  | ||||||
|             body: JSON.stringify(certificateRunners), |  | ||||||
|           } |  | ||||||
|         ) |  | ||||||
|           .then((response) => { |  | ||||||
|             if (response.status != "200") { |  | ||||||
|               toast.dismiss(); |  | ||||||
|               toast.error($_("pdf-generation-failed")); |  | ||||||
|             } else { |  | ||||||
|               return response.blob(); |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|           .then((blob) => { |           .then((blob) => { | ||||||
|             const url = window.URL.createObjectURL(blob); |             download( | ||||||
|             let a = document.createElement("a"); |               blob, | ||||||
|             a.href = url; |               `${$_("certificates")}_${o.name}_${ | ||||||
|             a.download = `${$_("certificates")}_${o.name}_${ |                 t.name | ||||||
|               t.name |               }-${locale}-${createId()}.pdf` | ||||||
|             }-${locale}-${createId()}.pdf`; |             ); | ||||||
|             document.body.appendChild(a); |  | ||||||
|             a.click(); |  | ||||||
|             a.remove(); |  | ||||||
|             if ( |             if ( | ||||||
|               count === o.teams.length && |               count === o.teams.length && | ||||||
|               count_orgs === generate_orgs.length |               count_orgs === generate_orgs.length | ||||||
|             ) { |             ) { | ||||||
|               toast.dismiss(); |               toast.dismiss(); | ||||||
|               toast($_("pdfs-successfully-generated")); |               toast.success($_("pdfs-successfully-generated")); | ||||||
|             } |             } | ||||||
|           }) |           }) | ||||||
|           .catch((err) => {}); |           .catch((err) => {}); | ||||||
| @@ -244,69 +161,20 @@ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if certificates_show} | {#if certificates_show} | ||||||
|   <div id="certificates:dropdown" class="relative inline-block"> |   <button | ||||||
|     <div> |     on:click={() => { | ||||||
|       <button |       generateCertificates("de"); | ||||||
|         on:click={() => { |     }} | ||||||
|           certificates_dropdown_open = !certificates_dropdown_open; |     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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|         }} |   > | ||||||
|         type="button" |     {$_("generate-runner-certificates")}: DE | ||||||
|         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" |   </button> | ||||||
|         id="options-menu" |   <button | ||||||
|         aria-haspopup="true" |     on:click={() => { | ||||||
|         aria-expanded="true" |       generateCertificates("en"); | ||||||
|       > |     }} | ||||||
|         {$_("generate-runner-certificates")} |     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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|         <svg |   > | ||||||
|           xmlns="http://www.w3.org/2000/svg" |     {$_("generate-runner-certificates")}: EN | ||||||
|           width="24" |   </button> | ||||||
|           height="24" |  | ||||||
|           viewBox="0 0 24 24" |  | ||||||
|           class="-mr-1 ml-2 h-5 w-5" |  | ||||||
|           ><path fill="none" d="M0 0h24v24H0z" /> |  | ||||||
|           <path |  | ||||||
|             fill="currentColor" |  | ||||||
|             d="M3 19h18v2H3v-2zm10-5.83l6.07-6.07 1.42 1.41L12 17 3.52 8.52l1.4-1.42L11 13.17V2h2v11.17z" |  | ||||||
|           /></svg |  | ||||||
|         > |  | ||||||
|       </button> |  | ||||||
|     </div> |  | ||||||
|     {#if certificates_dropdown_open} |  | ||||||
|       <div |  | ||||||
|         class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 z-10" |  | ||||||
|         id="certificates:dropdown:menu" |  | ||||||
|       > |  | ||||||
|         <div |  | ||||||
|           class="py-1" |  | ||||||
|           role="menu" |  | ||||||
|           aria-orientation="vertical" |  | ||||||
|           aria-labelledby="options-menu" |  | ||||||
|         > |  | ||||||
|           <span class="block w-full text-left px-4 py-2 text-sm text-gray-700" |  | ||||||
|             >{$_("select-language")}</span |  | ||||||
|           > |  | ||||||
|           <button |  | ||||||
|             on:click={() => { |  | ||||||
|               generateCertificates("de"); |  | ||||||
|             }} |  | ||||||
|             type="submit" |  | ||||||
|             class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" |  | ||||||
|             role="menuitem" |  | ||||||
|           > |  | ||||||
|             {$_("german")} |  | ||||||
|           </button> |  | ||||||
|           <button |  | ||||||
|             on:click={() => { |  | ||||||
|               generateCertificates("en"); |  | ||||||
|             }} |  | ||||||
|             type="submit" |  | ||||||
|             class="block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" |  | ||||||
|             role="menuitem" |  | ||||||
|           > |  | ||||||
|             {$_("english")} |  | ||||||
|           </button> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     {/if} |  | ||||||
|   </div> |  | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -1,283 +1,163 @@ | |||||||
| <script> | <script> | ||||||
|   import { getLocaleFromNavigator, _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import { | 	import { | ||||||
|     RunnerOrganizationService, | 		RunnerOrganizationService, | ||||||
|     RunnerTeamService, | 		RunnerTeamService, | ||||||
|   } from "@odit/lfk-client-js"; | 	} from "@odit/lfk-client-js"; | ||||||
|  | 	import DocumentServer from "./DocumentServer"; | ||||||
|  | 	import { init } from "@paralleldrive/cuid2"; | ||||||
|  | 	import toast from "svelte-french-toast"; | ||||||
|  | 	import DownloadProgressModal from "./DownloadProgressModal.svelte"; | ||||||
|  | 	const createId = init({ length: 10, fingerprint: "lfk-frontend" }); | ||||||
|  | 	const documentServer = new DocumentServer( | ||||||
|  | 		config.baseurl_documentserver, | ||||||
|  | 		config.documentserver_key | ||||||
|  | 	); | ||||||
|  |  | ||||||
|   import { init } from "@paralleldrive/cuid2"; | 	export let sponsoring_contracts_show = false; | ||||||
|   import toast from "svelte-french-toast"; | 	export let generate_runners = []; | ||||||
|   const createId = init({ length: 10, fingerprint: "lfk-frontend" }); | 	export let generate_orgs = []; | ||||||
|  | 	export let generate_teams = []; | ||||||
|  | 	// | ||||||
|  | 	export let download_modal_open = false; | ||||||
|  | 	export let download_details = ""; | ||||||
|  |  | ||||||
|   export let sponsoring_contracts_show = false; | 	function generateSponsoringContract(locale) { | ||||||
|   export let generate_runners = []; | 		download_modal_open = true; | ||||||
|   export let generate_orgs = []; | 		if (generate_orgs.length > 0) { | ||||||
|   export let generate_teams = []; | 			generateOrgContracts(locale); | ||||||
|   $: sponsoring_contracts_download_open = false; | 		} else if (generate_teams.length > 0) { | ||||||
|   document.addEventListener("click", function (e) { | 			generateTeamContracts(locale); | ||||||
|     if ( | 		} else { | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown" && | 			generateRunnerContracts(locale); | ||||||
|       e.target.parentNode?.parentNode?.id != "sponsoring:dropdown:menu" | 		} | ||||||
|     ) { | 	} | ||||||
|       sponsoring_contracts_download_open = false; | 	function download(blob, fileName) { | ||||||
|     } | 		const url = window.URL.createObjectURL(blob); | ||||||
|   }); | 		let a = document.createElement("a"); | ||||||
|  | 		a.href = url; | ||||||
|  | 		a.download = fileName; | ||||||
|  | 		document.body.appendChild(a); | ||||||
|  | 		a.click(); | ||||||
|  | 		a.remove(); | ||||||
|  | 		toast.dismiss(); | ||||||
|  | 		toast.success($_("pdf-successfully-generated")); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|   function generateSponsoringContract(locale) { | 	async function generateTeamContracts(locale) { | ||||||
|     sponsoring_contracts_download_open = false; | 		toast.loading($_("generating-pdfs")); | ||||||
|  | 		let totalCount = generate_teams.length; | ||||||
|  | 		let count = 0; | ||||||
|  | 		for (const t of generate_teams) { | ||||||
|  | 			count++; | ||||||
|  | 			download_details = `${t.parentGroup.name} > ${t.name}`; | ||||||
|  | 			const runners = await RunnerTeamService.runnerTeamControllerGetRunners( | ||||||
|  | 				t.id | ||||||
|  | 			); | ||||||
|  | 			await documentServer | ||||||
|  | 				.generateContracts(runners, locale) | ||||||
|  | 				.then((blob) => { | ||||||
|  | 					download( | ||||||
|  | 						blob, | ||||||
|  | 						`${$_("sponsorings")}_${t.name}-${locale}-${createId()}.pdf` | ||||||
|  | 					); | ||||||
|  | 					if (count === totalCount) { | ||||||
|  | 						download_modal_open = false; | ||||||
|  | 					} | ||||||
|  | 				}) | ||||||
|  | 				.catch((err) => {}); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|     if (generate_orgs.length > 0) { | 	async function generateOrgContracts(locale) { | ||||||
|       generateOrgContracts(locale); | 		toast.loading($_("generating-pdf")); | ||||||
|     } else if (generate_teams.length > 0) { | 		let totalCount = 0; | ||||||
|       generateTeamContracts(locale); | 		for (const o of generate_orgs) { | ||||||
|     } else { | 			totalCount++; | ||||||
|       generateRunnerContracts(locale); | 			for (const t of o.teams) { | ||||||
|     } | 				totalCount++; | ||||||
|   } | 			} | ||||||
|  | 		} | ||||||
|  | 		console.log({ totalCount }); | ||||||
|  | 		let count = 0; | ||||||
|  | 		for (const o of generate_orgs) { | ||||||
|  | 			count++; | ||||||
|  | 			let runners = | ||||||
|  | 				await RunnerOrganizationService.runnerOrganizationControllerGetRunners( | ||||||
|  | 					o.id, | ||||||
|  | 					true | ||||||
|  | 				); | ||||||
|  | 			download_details = o.name; | ||||||
|  | 			await documentServer | ||||||
|  | 				.generateContracts(runners, locale) | ||||||
|  | 				.then((blob) => { | ||||||
|  | 					download( | ||||||
|  | 						blob, | ||||||
|  | 						`${$_("sponsorings")}_${o.name}_direct-${locale}-${createId()}.pdf` | ||||||
|  | 					); | ||||||
|  | 				}) | ||||||
|  | 				.catch((err) => {}); | ||||||
|  | 			for (const t of o.teams) { | ||||||
|  | 				count++; | ||||||
|  | 				let runners = await RunnerTeamService.runnerTeamControllerGetRunners( | ||||||
|  | 					t.id | ||||||
|  | 				); | ||||||
|  | 				download_details = `${o.name} > ${t.name}`; | ||||||
|  | 				await documentServer | ||||||
|  | 					.generateContracts(runners, locale) | ||||||
|  | 					.then((blob) => { | ||||||
|  | 						download( | ||||||
|  | 							blob, | ||||||
|  | 							`${$_("sponsorings")}_${o.name}_${ | ||||||
|  | 								t.name | ||||||
|  | 							}-${locale}-${createId()}.pdf` | ||||||
|  | 						); | ||||||
|  | 						console.log({ count }); | ||||||
|  | 						if (count === totalCount) { | ||||||
|  | 							download_modal_open = false; | ||||||
|  | 						} | ||||||
|  | 					}) | ||||||
|  | 					.catch((err) => {}); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|   async function generateTeamContracts(locale) { | 	async function generateRunnerContracts(locale) { | ||||||
|     toast.loading($_("generating-pdfs")); | 		toast.loading($_("generating-pdf")); | ||||||
|     let count = 0; | 		await documentServer | ||||||
|     for (const t of generate_teams) { | 			.generateContracts(generate_runners, locale) | ||||||
|       count++; | 			.then((blob) => { | ||||||
|       const runners = await RunnerTeamService.runnerTeamControllerGetRunners( | 				let fileName = `${$_("sponsorings")}-${locale}-${createId()}.pdf`; | ||||||
|         t.id | 				if (generate_runners.length == 1) { | ||||||
|       ); | 					fileName = `${$_("sponsorings")}_${generate_runners[0].firstname}_${ | ||||||
|       fetch( | 						generate_runners[0].lastname | ||||||
|         `${config.baseurl_documentserver}/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, | 					}-${locale}-${createId()}.pdf`; | ||||||
|         { | 				} | ||||||
|           method: "POST", | 				download(blob, fileName); | ||||||
|           headers: { | 				download_modal_open = false; | ||||||
|             "Content-Type": "application/json", | 			}) | ||||||
|           }, | 			.catch((err) => { | ||||||
|           body: JSON.stringify(runners), | 				console.error(err); | ||||||
|         } | 			}); | ||||||
|       ) | 	} | ||||||
|         .then((response) => { |  | ||||||
|           if (response.status != "200") { |  | ||||||
|             toast.dismiss(); |  | ||||||
|             toast.error($_("pdf-generation-failed")); |  | ||||||
|           } 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 |  | ||||||
|           }-${locale}-${createId()}.pdf`; |  | ||||||
|           document.body.appendChild(a); |  | ||||||
|           a.click(); |  | ||||||
|           a.remove(); |  | ||||||
|           if (count === generate_teams.length) { |  | ||||||
|             toast.dismiss(); |  | ||||||
|             toast.success($_("pdfs-successfully-generated")); |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|         .catch((err) => {}); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   async function generateOrgContracts(locale) { |  | ||||||
|     toast.loading($_("generating-pdf")); |  | ||||||
|     let count_orgs = 0; |  | ||||||
|     for (const o of generate_orgs) { |  | ||||||
|       count_orgs++; |  | ||||||
|       let count = 0; |  | ||||||
|       let runners = |  | ||||||
|         await RunnerOrganizationService.runnerOrganizationControllerGetRunners( |  | ||||||
|           o.id, |  | ||||||
|           true |  | ||||||
|         ); |  | ||||||
|       await fetch( |  | ||||||
|         `${config.baseurl_documentserver}/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, |  | ||||||
|         { |  | ||||||
|           method: "POST", |  | ||||||
|           headers: { |  | ||||||
|             "Content-Type": "application/json", |  | ||||||
|           }, |  | ||||||
|           body: JSON.stringify(runners), |  | ||||||
|         } |  | ||||||
|       ) |  | ||||||
|         .then((response) => { |  | ||||||
|           if (response.status != "200") { |  | ||||||
|             toast.dismiss(); |  | ||||||
|             toast.error($_("pdf-generation-failed")); |  | ||||||
|           } else { |  | ||||||
|             return response.blob(); |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|         .then((blob) => { |  | ||||||
|           const url = window.URL.createObjectURL(blob); |  | ||||||
|           let a = document.createElement("a"); |  | ||||||
|           a.href = url; |  | ||||||
|           a.download = `${$_("sponsorings")}_${ |  | ||||||
|             o.name |  | ||||||
|           }_direct-${locale}-${createId()}.pdf`; |  | ||||||
|           document.body.appendChild(a); |  | ||||||
|           a.click(); |  | ||||||
|           a.remove(); |  | ||||||
|           if (count === o.teams.length && count_orgs === generate_orgs.length) { |  | ||||||
|             toast.dismiss(); |  | ||||||
|             toast.success($_("pdfs-successfully-generated")); |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|         .catch((err) => {}); |  | ||||||
|       for (const t of o.teams) { |  | ||||||
|         count++; |  | ||||||
|         let runners = await RunnerTeamService.runnerTeamControllerGetRunners( |  | ||||||
|           t.id |  | ||||||
|         ); |  | ||||||
|         await fetch( |  | ||||||
|           `${config.baseurl_documentserver}/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, |  | ||||||
|           { |  | ||||||
|             method: "POST", |  | ||||||
|             headers: { |  | ||||||
|               "Content-Type": "application/json", |  | ||||||
|             }, |  | ||||||
|             body: JSON.stringify(runners), |  | ||||||
|           } |  | ||||||
|         ) |  | ||||||
|           .then((response) => { |  | ||||||
|             if (response.status != "200") { |  | ||||||
|               toast.dismiss(); |  | ||||||
|               toast.error($_("pdf-generation-failed")); |  | ||||||
|             } else { |  | ||||||
|               return response.blob(); |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|           .then((blob) => { |  | ||||||
|             const url = window.URL.createObjectURL(blob); |  | ||||||
|             let a = document.createElement("a"); |  | ||||||
|             a.href = url; |  | ||||||
|             a.download = `${$_("sponsorings")}_${o.name}_${ |  | ||||||
|               t.name |  | ||||||
|             }-${locale}-${createId()}.pdf`; |  | ||||||
|             document.body.appendChild(a); |  | ||||||
|             a.click(); |  | ||||||
|             a.remove(); |  | ||||||
|             if ( |  | ||||||
|               count === o.teams.length && |  | ||||||
|               count_orgs === generate_orgs.length |  | ||||||
|             ) { |  | ||||||
|               toast.dismiss(); |  | ||||||
|               toast($_("pdfs-successfully-generated")); |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|           .catch((err) => {}); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   function generateRunnerContracts(locale) { |  | ||||||
|     toast.loading($_("generating-pdf")); |  | ||||||
|     fetch( |  | ||||||
|       `${config.baseurl_documentserver}/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.dismiss(); |  | ||||||
|           toast.error($_("pdf-generation-failed")); |  | ||||||
|         } else { |  | ||||||
|           return response.blob(); |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|       .then((blob) => { |  | ||||||
|         const url = window.URL.createObjectURL(blob); |  | ||||||
|         let a = document.createElement("a"); |  | ||||||
|         a.href = url; |  | ||||||
|         if (generate_runners.length == 1) { |  | ||||||
|           a.download = `${$_("sponsorings")}_${generate_runners[0].firstname}_${ |  | ||||||
|             generate_runners[0].lastname |  | ||||||
|           }-${locale}-${createId()}.pdf`; |  | ||||||
|         } |  | ||||||
|         a.download = `${$_("sponsorings")}-${locale}-${createId()}.pdf`; |  | ||||||
|         document.body.appendChild(a); |  | ||||||
|         a.click(); |  | ||||||
|         a.remove(); |  | ||||||
|         toast.dismiss(); |  | ||||||
|         toast($_("pdf-successfully-generated")); |  | ||||||
|       }) |  | ||||||
|       .catch((err) => { |  | ||||||
|         console.error(err); |  | ||||||
|       }); |  | ||||||
|   } |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if sponsoring_contracts_show} | {#if sponsoring_contracts_show} | ||||||
|   <div id="sponsoring:dropdown" class="relative inline-block"> | 	<DownloadProgressModal {download_details} modal_open={download_modal_open} /> | ||||||
|     <div> | 	<button | ||||||
|       <button | 		on:click={() => { | ||||||
|         on:click={() => { | 			generateSponsoringContract("de"); | ||||||
|           sponsoring_contracts_download_open = | 		}} | ||||||
|             !sponsoring_contracts_download_open; | 		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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|         }} | 	> | ||||||
|         type="button" | 		{$_("generate-sponsoring-contracts")}: DE | ||||||
|         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" | 	</button> | ||||||
|         id="options-menu" | 	<button | ||||||
|         aria-haspopup="true" | 		on:click={() => { | ||||||
|         aria-expanded="true" | 			generateSponsoringContract("en"); | ||||||
|       > | 		}} | ||||||
|         {$_("generate-sponsoring-contracts")} | 		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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|         <svg | 	> | ||||||
|           xmlns="http://www.w3.org/2000/svg" | 		{$_("generate-sponsoring-contracts")}: EN | ||||||
|           width="24" | 	</button> | ||||||
|           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 z-10" |  | ||||||
|         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} | {/if} | ||||||
|   | |||||||
| @@ -1,92 +0,0 @@ | |||||||
| <h3 class="text-lg">Standard Avatars</h3> |  | ||||||
| <div class="relative rounded-full w-4 h-4"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
| </div> |  | ||||||
| <div class="relative rounded-full w-8 h-8"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
| </div> |  | ||||||
| <div class="relative rounded-full w-12 h-12"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
| </div> |  | ||||||
| <div class="relative rounded-full w-16 h-16"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
| </div> |  | ||||||
| <div class="relative rounded-full w-20 h-20"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
| </div> |  | ||||||
| <div class="relative rounded-full w-24 h-24"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
| </div> |  | ||||||
| <h3 class="text-lg">Status Avatars</h3> |  | ||||||
| <div class="relative rounded-full w-4 h-4"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
|   <div class="absolute rounded-full right-0 bottom-0 w-1 h-1 bg-gray-200" /> |  | ||||||
| </div> |  | ||||||
| <div class="relative rounded-full w-8 h-8"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
|   <div class="absolute rounded-full right-0 bottom-0 w-2 h-2 bg-green-400" /> |  | ||||||
| </div> |  | ||||||
| <div class="relative rounded-full w-12 h-12"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
|   <div class="absolute rounded-full right-0 bottom-0 w-4 h-4 bg-red-600" /> |  | ||||||
| </div> |  | ||||||
| <div class="relative rounded-full w-16 h-16"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
|   <div class="absolute rounded-full right-0 bottom-0 w-5 h-5 bg-gray-200" /> |  | ||||||
| </div> |  | ||||||
| <div class="relative rounded-full w-20 h-20"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
|   <div class="absolute rounded-full right-0 bottom-0 w-6 h-6 bg-green-400" /> |  | ||||||
| </div> |  | ||||||
| <div class="relative rounded-full w-24 h-24"> |  | ||||||
|   <img |  | ||||||
|     alt="" |  | ||||||
|     src="https://gustui.s3.amazonaws.com/avatar.png" |  | ||||||
|     class="absolute left-0 top-0 w-full h-full rounded-full object-cover" |  | ||||||
|   /> |  | ||||||
|   <div class="absolute rounded-full right-0 bottom-0 w-6 h-6 bg-red-600" /> |  | ||||||
| </div> |  | ||||||
| @@ -1,65 +0,0 @@ | |||||||
| <h3 class="text-lg">badges</h3> |  | ||||||
| <span |  | ||||||
|   class="text-sm font-medium bg-green-100 py-1 px-2 rounded text-green-500 align-middle" |  | ||||||
|   >Paid</span |  | ||||||
| > |  | ||||||
| <span |  | ||||||
|   class="text-sm font-medium bg-red-100 py-1 px-2 rounded text-red-500 align-middle" |  | ||||||
|   >Overdue</span |  | ||||||
| > |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-blue-600" |  | ||||||
|   >Primary</span |  | ||||||
| > |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-gray-600" |  | ||||||
|   >Secondary</span |  | ||||||
| > |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-green-600" |  | ||||||
|   >Success</span |  | ||||||
| > |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-red-600" |  | ||||||
|   >Danger</span |  | ||||||
| > |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-black bg-yellow-400" |  | ||||||
|   >Warning</span |  | ||||||
| > |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-indigo-300" |  | ||||||
|   >Info</span |  | ||||||
| > |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-black bg-gray-200" |  | ||||||
|   >Light</span |  | ||||||
| > |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-gray-900" |  | ||||||
|   >Dark</span |  | ||||||
| > |  | ||||||
| <h3 class="text-lg">closable badges</h3> |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-blue-600"> |  | ||||||
|   Primary |  | ||||||
|   <span class="ml-2 text-base cursor-pointer">×</span> |  | ||||||
| </span> |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-gray-600"> |  | ||||||
|   Secondary |  | ||||||
|   <span class="ml-2 text-base cursor-pointer">×</span> |  | ||||||
| </span> |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-green-600"> |  | ||||||
|   Success |  | ||||||
|   <span class="ml-2 text-base cursor-pointer">×</span> |  | ||||||
| </span> |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-red-600"> |  | ||||||
|   Danger |  | ||||||
|   <span class="ml-2 text-base cursor-pointer">×</span> |  | ||||||
| </span> |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-black bg-yellow-400"> |  | ||||||
|   Warning |  | ||||||
|   <span class="ml-2 text-base cursor-pointer">×</span> |  | ||||||
| </span> |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-indigo-300"> |  | ||||||
|   Info |  | ||||||
|   <span class="ml-2 text-base cursor-pointer">×</span> |  | ||||||
| </span> |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-black bg-gray-200"> |  | ||||||
|   Light<span class="ml-2 text-base cursor-pointer">×</span> |  | ||||||
| </span> |  | ||||||
| <span class="rounded-sm py-1 px-2 text-xs font-medium text-white bg-gray-900"> |  | ||||||
|   Dark |  | ||||||
|   <span class="ml-2 text-base cursor-pointer">×</span> |  | ||||||
| </span> |  | ||||||
| @@ -1,59 +0,0 @@ | |||||||
| <div class="flex flex-row mb-4"> |  | ||||||
|   <div class="w-full"> |  | ||||||
|     <nav class="w-full flex"> |  | ||||||
|       <ol class="list-none flex flex-row items-center justify-start"> |  | ||||||
|         <li class="mr-2 flex items-center"> |  | ||||||
|           <svg |  | ||||||
|             stroke="currentColor" |  | ||||||
|             fill="none" |  | ||||||
|             stroke-width="2" |  | ||||||
|             viewBox="0 0 24 24" |  | ||||||
|             stroke-linecap="round" |  | ||||||
|             stroke-linejoin="round" |  | ||||||
|             class="h-3 w-3 stroke-current" |  | ||||||
|             height="1em" |  | ||||||
|             width="1em" |  | ||||||
|             xmlns="http://www.w3.org/2000/svg" |  | ||||||
|             ><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /> |  | ||||||
|             <polyline points="9 22 9 12 15 12 15 22" /></svg |  | ||||||
|           > |  | ||||||
|         </li> |  | ||||||
|         <li class="flex items-center"> |  | ||||||
|           <a class="mr-2" href="/">Home</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"> |  | ||||||
|           <a class="mr-2" href="/">Second level</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"> |  | ||||||
|           <a class="mr-2" href="/">Third level</a> |  | ||||||
|         </li> |  | ||||||
|       </ol> |  | ||||||
|     </nav> |  | ||||||
|   </div> |  | ||||||
| </div> |  | ||||||
| @@ -1,80 +0,0 @@ | |||||||
| <script> |  | ||||||
|   import Avatars from "./Avatars.svelte"; |  | ||||||
|   import Badges from "./Badges.svelte"; |  | ||||||
|   import BreadcrumbNav from "./BreadcrumbNav.svelte"; |  | ||||||
|   import FileUpload from "./FileUpload.svelte"; |  | ||||||
|   import Pagination from "./Pagination.svelte"; |  | ||||||
|   import Table from "./Table.svelte"; |  | ||||||
|   import Tabs from "./Tabs.svelte"; |  | ||||||
|   import Tags from "./Tags.svelte"; |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <div class="border-4 border-dashed rounded h-96 mb-4" /> |  | ||||||
| <div class="mb-8"> |  | ||||||
|   <FileUpload /> |  | ||||||
| </div> |  | ||||||
| <div class="mb-8"> |  | ||||||
|   <Tabs /> |  | ||||||
| </div> |  | ||||||
| <div class="mb-8"> |  | ||||||
|   <Tags /> |  | ||||||
| </div> |  | ||||||
| <div class="mb-8"> |  | ||||||
|   <Badges /> |  | ||||||
| </div> |  | ||||||
| <div class="mb-8"> |  | ||||||
|   <Avatars /> |  | ||||||
| </div> |  | ||||||
| <Pagination /> |  | ||||||
| <div class="mb-8"> |  | ||||||
|   <Table /> |  | ||||||
| </div> |  | ||||||
| <div class="widget w-full p-4 mb-4 rounded-lg bg-white border border-grey-100"> |  | ||||||
|   <div class="flex flex-row items-center justify-between mb-6"> |  | ||||||
|     <div class="flex flex-col"> |  | ||||||
|       <div class="text-sm font-light text-grey-500">Regular</div> |  | ||||||
|       <div class="text-sm font-bold"><span>Text inputs</span></div> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
|   <div class="flex flex-col lg:flex-row lg:flex-wrap w-full lg:space-x-4"> |  | ||||||
|     <div class="w-full lg:w-1/4"> |  | ||||||
|       <div class="form-element"> |  | ||||||
|         <div class="form-label">Label</div> |  | ||||||
|         <input |  | ||||||
|           name="name" |  | ||||||
|           type="text" |  | ||||||
|           class="form-input" |  | ||||||
|           placeholder="Enter something..." |  | ||||||
|         /> |  | ||||||
|         <div class="form-hint">This is a hint</div> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|     <div class="w-full lg:w-1/4"> |  | ||||||
|       <div class="form-element"> |  | ||||||
|         <div class="form-label">First name</div> |  | ||||||
|         <input |  | ||||||
|           name="name" |  | ||||||
|           type="text" |  | ||||||
|           class="form-input form-input-invalid" |  | ||||||
|           placeholder="john@example.com" |  | ||||||
|         /> |  | ||||||
|         <div class="form-error">First name is required</div> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|     <div class="w-full lg:w-1/4"> |  | ||||||
|       <div class="form-element"> |  | ||||||
|         <div class="form-label">First name</div> |  | ||||||
|         <input |  | ||||||
|           name="name" |  | ||||||
|           type="text" |  | ||||||
|           class="form-input form-input-valid" |  | ||||||
|           placeholder="john@example.com" |  | ||||||
|         /> |  | ||||||
|         <div class="form-success">First name is valid</div> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </div> |  | ||||||
| <div class="mb-8"> |  | ||||||
|   <BreadcrumbNav /> |  | ||||||
| </div> |  | ||||||
| @@ -1,643 +0,0 @@ | |||||||
| <div class="w-full p-4 rounded-lg bg-white border border-grey-100"> |  | ||||||
|   <div class="flex flex-row items-center justify-between mb-6"> |  | ||||||
|     <div class="flex flex-col"> |  | ||||||
|       <div class="text-sm font-light text-grey-500">Conversions</div> |  | ||||||
|       <div class="text-sm font-bold"><span>This year</span></div> |  | ||||||
|     </div> |  | ||||||
|     <div class="relative"> |  | ||||||
|       <button |  | ||||||
|         class="btn btn-default btn-circle btn-icon bg-transparent hover:bg-transparent active:bg-transparent relative" |  | ||||||
|         ><svg |  | ||||||
|           stroke="currentColor" |  | ||||||
|           fill="none" |  | ||||||
|           stroke-width="2" |  | ||||||
|           viewBox="0 0 24 24" |  | ||||||
|           stroke-linecap="round" |  | ||||||
|           stroke-linejoin="round" |  | ||||||
|           class="stroke-current stroke-1" |  | ||||||
|           size="18" |  | ||||||
|           height="18" |  | ||||||
|           width="18" |  | ||||||
|           xmlns="http://www.w3.org/2000/svg" |  | ||||||
|         > |  | ||||||
|           <circle cx="12" cy="12" r="1" /> |  | ||||||
|           <circle cx="12" cy="5" r="1" /> |  | ||||||
|           <circle cx="12" cy="19" r="1" /> |  | ||||||
|         </svg></button |  | ||||||
|       > |  | ||||||
|       <div class="dropdown absolute top-0 right-0 mt-8"> |  | ||||||
|         <div class="dropdown-content w-48 bottom-start"> |  | ||||||
|           <div class="flex flex-col w-full"> |  | ||||||
|             <ul class="list-none"> |  | ||||||
|               <li> |  | ||||||
|                 <a |  | ||||||
|                   class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100" |  | ||||||
|                   href="/">Today</a |  | ||||||
|                 > |  | ||||||
|               </li> |  | ||||||
|               <li> |  | ||||||
|                 <a |  | ||||||
|                   class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100" |  | ||||||
|                   href="/">This week</a |  | ||||||
|                 > |  | ||||||
|               </li> |  | ||||||
|               <li> |  | ||||||
|                 <a |  | ||||||
|                   class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100" |  | ||||||
|                   href="/">This month</a |  | ||||||
|                 > |  | ||||||
|               </li> |  | ||||||
|               <li> |  | ||||||
|                 <a |  | ||||||
|                   class="flex flex-row items-center justify-start h-10 w-full px-2 bg-white hover:bg-grey-100" |  | ||||||
|                   href="/">This year</a |  | ||||||
|                 > |  | ||||||
|               </li> |  | ||||||
|             </ul> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
|   <div class="flex flex-row w-full"> |  | ||||||
|     <div style="width:100%;height:240px"> |  | ||||||
|       <div class="recharts-responsive-container" style="width:100%;height:100%"> |  | ||||||
|         <div |  | ||||||
|           class="recharts-wrapper" |  | ||||||
|           style="position: relative; cursor: default; width: 704px; height: 240px;" |  | ||||||
|         > |  | ||||||
|           <svg |  | ||||||
|             class="recharts-surface" |  | ||||||
|             width="704" |  | ||||||
|             height="240" |  | ||||||
|             viewBox="0 0 704 240" |  | ||||||
|             version="1.1" |  | ||||||
|           > |  | ||||||
|             <defs> |  | ||||||
|               <clipPath id="recharts3-clip"> |  | ||||||
|                 <rect x="40" y="10" height="190" width="654" /> |  | ||||||
|               </clipPath> |  | ||||||
|             </defs> |  | ||||||
|             <g |  | ||||||
|               class="recharts-layer recharts-cartesian-axis recharts-xAxis xAxis" |  | ||||||
|             > |  | ||||||
|               <g class="recharts-cartesian-axis-ticks"> |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="67.25" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="67.25" dy="0.71em">Jan</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="121.75" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="121.75" dy="0.71em">Feb</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="176.25" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="176.25" dy="0.71em">Mar</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="230.75" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="230.75" dy="0.71em">Apr</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="285.25" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="285.25" dy="0.71em">May</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="339.75" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="339.75" dy="0.71em">Jun</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="394.25" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="394.25" dy="0.71em">Jul</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="448.75" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="448.75" dy="0.71em">Aug</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="503.25" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="503.25" dy="0.71em">Sep</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="557.75" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="557.75" dy="0.71em">Oct</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="612.25" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="612.25" dy="0.71em">Nov</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="654" |  | ||||||
|                     height="30" |  | ||||||
|                     x="666.75" |  | ||||||
|                     y="208" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="middle" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="666.75" dy="0.71em">Dec</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|               </g> |  | ||||||
|             </g> |  | ||||||
|             <g |  | ||||||
|               class="recharts-layer recharts-cartesian-axis recharts-yAxis yAxis" |  | ||||||
|             > |  | ||||||
|               <g class="recharts-cartesian-axis-ticks"> |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="30" |  | ||||||
|                     height="190" |  | ||||||
|                     x="32" |  | ||||||
|                     y="200" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="end" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="32" dy="0.355em">0</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="30" |  | ||||||
|                     height="190" |  | ||||||
|                     x="32" |  | ||||||
|                     y="152.5" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="end" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="32" dy="0.355em">65</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="30" |  | ||||||
|                     height="190" |  | ||||||
|                     x="32" |  | ||||||
|                     y="105" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="end" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="32" dy="0.355em">130</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="30" |  | ||||||
|                     height="190" |  | ||||||
|                     x="32" |  | ||||||
|                     y="57.5" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="end" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="32" dy="0.355em">195</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|                 <g class="recharts-layer recharts-cartesian-axis-tick" |  | ||||||
|                   ><text |  | ||||||
|                     width="30" |  | ||||||
|                     height="190" |  | ||||||
|                     x="32" |  | ||||||
|                     y="10" |  | ||||||
|                     stroke="none" |  | ||||||
|                     fill="#666" |  | ||||||
|                     class="recharts-text recharts-cartesian-axis-tick-value" |  | ||||||
|                     text-anchor="end" |  | ||||||
|                   > |  | ||||||
|                     <tspan x="32" dy="0.355em">260</tspan> |  | ||||||
|                   </text></g |  | ||||||
|                 > |  | ||||||
|               </g> |  | ||||||
|             </g> |  | ||||||
|             <g class="recharts-layer recharts-bar"> |  | ||||||
|               <g class="recharts-layer recharts-bar-rectangles"> |  | ||||||
|                 <g class="recharts-layer"> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="119.11538461538461" |  | ||||||
|                       x="55" |  | ||||||
|                       y="80.88461538461539" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 55,80.88461538461539 h 10 v 119.11538461538461 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="95" |  | ||||||
|                       x="109.5" |  | ||||||
|                       y="105" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 109.5,105 h 10 v 95 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="122.03846153846155" |  | ||||||
|                       x="164" |  | ||||||
|                       y="77.96153846153845" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 164,77.96153846153845 h 10 v 122.03846153846155 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="81.11538461538461" |  | ||||||
|                       x="218.5" |  | ||||||
|                       y="118.88461538461539" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 218.5,118.88461538461539 h 10 v 81.11538461538461 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="114" |  | ||||||
|                       x="273" |  | ||||||
|                       y="86" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 273,86 h 10 v 114 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="117.65384615384616" |  | ||||||
|                       x="327.5" |  | ||||||
|                       y="82.34615384615384" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 327.5,82.34615384615384 h 10 v 117.65384615384616 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="103.76923076923076" |  | ||||||
|                       x="382" |  | ||||||
|                       y="96.23076923076924" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 382,96.23076923076924 h 10 v 103.76923076923076 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="92.80769230769232" |  | ||||||
|                       x="436.5" |  | ||||||
|                       y="107.19230769230768" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 436.5,107.19230769230768 h 10 v 92.80769230769232 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="92.80769230769232" |  | ||||||
|                       x="491" |  | ||||||
|                       y="107.19230769230768" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 491,107.19230769230768 h 10 v 92.80769230769232 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="127.8846153846154" |  | ||||||
|                       x="545.5" |  | ||||||
|                       y="72.1153846153846" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 545.5,72.1153846153846 h 10 v 127.8846153846154 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="105.23076923076924" |  | ||||||
|                       x="600" |  | ||||||
|                       y="94.76923076923076" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 600,94.76923076923076 h 10 v 105.23076923076924 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#90caf9" |  | ||||||
|                       width="10" |  | ||||||
|                       height="115.46153846153845" |  | ||||||
|                       x="654.5" |  | ||||||
|                       y="84.53846153846155" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 654.5,84.53846153846155 h 10 v 115.46153846153845 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                 </g> |  | ||||||
|               </g> |  | ||||||
|             </g> |  | ||||||
|             <g class="recharts-layer recharts-bar"> |  | ||||||
|               <g class="recharts-layer recharts-bar-rectangles"> |  | ||||||
|                 <g class="recharts-layer"> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="112.53846153846155" |  | ||||||
|                       x="69" |  | ||||||
|                       y="87.46153846153845" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 69,87.46153846153845 h 10 v 112.53846153846155 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="151.26923076923077" |  | ||||||
|                       x="123.5" |  | ||||||
|                       y="48.730769230769226" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 123.5,48.730769230769226 h 10 v 151.26923076923077 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="181.23076923076923" |  | ||||||
|                       x="178" |  | ||||||
|                       y="18.769230769230774" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 178,18.769230769230774 h 10 v 181.23076923076923 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="165.8846153846154" |  | ||||||
|                       x="232.5" |  | ||||||
|                       y="34.11538461538461" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 232.5,34.11538461538461 h 10 v 165.8846153846154 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="156.38461538461536" |  | ||||||
|                       x="287" |  | ||||||
|                       y="43.61538461538464" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 287,43.61538461538464 h 10 v 156.38461538461536 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="118.38461538461539" |  | ||||||
|                       x="341.5" |  | ||||||
|                       y="81.61538461538461" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 341.5,81.61538461538461 h 10 v 118.38461538461539 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="138.84615384615384" |  | ||||||
|                       x="396" |  | ||||||
|                       y="61.15384615384616" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 396,61.15384615384616 h 10 v 138.84615384615384 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="175.3846153846154" |  | ||||||
|                       x="450.5" |  | ||||||
|                       y="24.615384615384613" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 450.5,24.615384615384613 h 10 v 175.3846153846154 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="155.65384615384613" |  | ||||||
|                       x="505" |  | ||||||
|                       y="44.34615384615387" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 505,44.34615384615387 h 10 v 155.65384615384613 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="179.76923076923077" |  | ||||||
|                       x="559.5" |  | ||||||
|                       y="20.230769230769226" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 559.5,20.230769230769226 h 10 v 179.76923076923077 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="173.19230769230768" |  | ||||||
|                       x="614" |  | ||||||
|                       y="26.80769230769232" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 614,26.80769230769232 h 10 v 173.19230769230768 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                   <g class="recharts-layer recharts-bar-rectangle"> |  | ||||||
|                     <path |  | ||||||
|                       fill="#1e88e5" |  | ||||||
|                       width="10" |  | ||||||
|                       height="146.15384615384616" |  | ||||||
|                       x="668.5" |  | ||||||
|                       y="53.84615384615384" |  | ||||||
|                       radius="0" |  | ||||||
|                       class="recharts-rectangle" |  | ||||||
|                       d="M 668.5,53.84615384615384 h 10 v 146.15384615384616 h -10 Z" |  | ||||||
|                     /> |  | ||||||
|                   </g> |  | ||||||
|                 </g> |  | ||||||
|               </g> |  | ||||||
|             </g> |  | ||||||
|           </svg> |  | ||||||
|           <div |  | ||||||
|             class="recharts-tooltip-wrapper" |  | ||||||
|             style="pointer-events: none; visibility: hidden; position: absolute; top: 0px; transform: translate(538.875px, 126px);" |  | ||||||
|           /> |  | ||||||
|         </div> |  | ||||||
|         <div |  | ||||||
|           style="position:absolute;width:0;height:0;visibility:hidden;display:none" |  | ||||||
|         /> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </div> |  | ||||||
| @@ -1,120 +0,0 @@ | |||||||
| <!-- This example requires Tailwind CSS v2.0+ --> |  | ||||||
| <div |  | ||||||
|   class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6" |  | ||||||
| > |  | ||||||
|   <div class="flex-1 flex justify-between sm:hidden"> |  | ||||||
|     <a |  | ||||||
|       href="#" |  | ||||||
|       class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:text-gray-500" |  | ||||||
|     > |  | ||||||
|       Previous |  | ||||||
|     </a> |  | ||||||
|     <a |  | ||||||
|       href="#" |  | ||||||
|       class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:text-gray-500" |  | ||||||
|     > |  | ||||||
|       Next |  | ||||||
|     </a> |  | ||||||
|   </div> |  | ||||||
|   <div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between"> |  | ||||||
|     <div> |  | ||||||
|       <p class="text-sm text-gray-700"> |  | ||||||
|         Showing |  | ||||||
|         <span class="font-medium">1</span> |  | ||||||
|         to |  | ||||||
|         <span class="font-medium">10</span> |  | ||||||
|         of |  | ||||||
|         <span class="font-medium">97</span> |  | ||||||
|         results |  | ||||||
|       </p> |  | ||||||
|     </div> |  | ||||||
|     <div> |  | ||||||
|       <nav |  | ||||||
|         class="relative z-0 inline-flex shadow-sm -space-x-px" |  | ||||||
|         aria-label="Pagination" |  | ||||||
|       > |  | ||||||
|         <a |  | ||||||
|           href="#" |  | ||||||
|           class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50" |  | ||||||
|         > |  | ||||||
|           <span class="sr-only">Previous</span> |  | ||||||
|           <!-- Heroicon name: chevron-left --> |  | ||||||
|           <svg |  | ||||||
|             class="h-5 w-5" |  | ||||||
|             xmlns="http://www.w3.org/2000/svg" |  | ||||||
|             viewBox="0 0 20 20" |  | ||||||
|             fill="currentColor" |  | ||||||
|             aria-hidden="true" |  | ||||||
|           > |  | ||||||
|             <path |  | ||||||
|               fill-rule="evenodd" |  | ||||||
|               d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" |  | ||||||
|               clip-rule="evenodd" |  | ||||||
|             /> |  | ||||||
|           </svg> |  | ||||||
|         </a> |  | ||||||
|         <a |  | ||||||
|           href="#" |  | ||||||
|           class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50" |  | ||||||
|         > |  | ||||||
|           1 |  | ||||||
|         </a> |  | ||||||
|         <a |  | ||||||
|           href="#" |  | ||||||
|           class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50" |  | ||||||
|         > |  | ||||||
|           2 |  | ||||||
|         </a> |  | ||||||
|         <a |  | ||||||
|           href="#" |  | ||||||
|           class="hidden md:inline-flex relative items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50" |  | ||||||
|         > |  | ||||||
|           3 |  | ||||||
|         </a> |  | ||||||
|         <span |  | ||||||
|           class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700" |  | ||||||
|         > |  | ||||||
|           ... |  | ||||||
|         </span> |  | ||||||
|         <a |  | ||||||
|           href="#" |  | ||||||
|           class="hidden md:inline-flex relative items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50" |  | ||||||
|         > |  | ||||||
|           8 |  | ||||||
|         </a> |  | ||||||
|         <a |  | ||||||
|           href="#" |  | ||||||
|           class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50" |  | ||||||
|         > |  | ||||||
|           9 |  | ||||||
|         </a> |  | ||||||
|         <a |  | ||||||
|           href="#" |  | ||||||
|           class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50" |  | ||||||
|         > |  | ||||||
|           10 |  | ||||||
|         </a> |  | ||||||
|         <a |  | ||||||
|           href="#" |  | ||||||
|           class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50" |  | ||||||
|         > |  | ||||||
|           <span class="sr-only">Next</span> |  | ||||||
|           <!-- Heroicon name: chevron-right --> |  | ||||||
|           <svg |  | ||||||
|             class="h-5 w-5" |  | ||||||
|             xmlns="http://www.w3.org/2000/svg" |  | ||||||
|             viewBox="0 0 20 20" |  | ||||||
|             fill="currentColor" |  | ||||||
|             aria-hidden="true" |  | ||||||
|           > |  | ||||||
|             <path |  | ||||||
|               fill-rule="evenodd" |  | ||||||
|               d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" |  | ||||||
|               clip-rule="evenodd" |  | ||||||
|             /> |  | ||||||
|           </svg> |  | ||||||
|         </a> |  | ||||||
|       </nav> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </div> |  | ||||||
| @@ -1,289 +0,0 @@ | |||||||
| <div class="min-h-screen w-full p-4"> |  | ||||||
|   <div class="section-title w-full mb-6 pt-3"> |  | ||||||
|     <div class="flex flex-row items-center justify-between mb-4"> |  | ||||||
|       <div class="flex flex-col"> |  | ||||||
|         <div class="text-xs uppercase font-light text-grey-500">Pages</div> |  | ||||||
|         <div class="text-xl font-bold">User profile</div> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
|   <div class="w-full p-4 mb-4 rounded-lg bg-white border border-grey-100"> |  | ||||||
|     <div class="flex flex-row items-center justify-start p-4"> |  | ||||||
|       <div class="flex-shrink-0 w-24"> |  | ||||||
|         <img |  | ||||||
|           src="/images/faces/m1.png" |  | ||||||
|           alt="media" |  | ||||||
|           class="shadow rounded-full h-20 w-20 shadow-outline mb-2" |  | ||||||
|         /> |  | ||||||
|       </div> |  | ||||||
|       <div class="py-2 px-2"> |  | ||||||
|         <p class="text-base font-bold whitespace-no-wrap">Lucas Smith</p> |  | ||||||
|         <p class="text-sm text-grey-500 whitespace-no-wrap"> |  | ||||||
|           Vital Database Dude |  | ||||||
|         </p> |  | ||||||
|         <div |  | ||||||
|           class="flex flex-row items-center justify-start w-full py-1 space-x-2" |  | ||||||
|         > |  | ||||||
|           <svg |  | ||||||
|             stroke="currentColor" |  | ||||||
|             fill="none" |  | ||||||
|             stroke-width="2" |  | ||||||
|             viewBox="0 0 24 24" |  | ||||||
|             stroke-linecap="round" |  | ||||||
|             stroke-linejoin="round" |  | ||||||
|             class="stroke-current text-xl text-twitter" |  | ||||||
|             height="1em" |  | ||||||
|             width="1em" |  | ||||||
|             xmlns="http://www.w3.org/2000/svg" |  | ||||||
|             ><path |  | ||||||
|               d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z" |  | ||||||
|             /></svg |  | ||||||
|           ><svg |  | ||||||
|             stroke="currentColor" |  | ||||||
|             fill="none" |  | ||||||
|             stroke-width="2" |  | ||||||
|             viewBox="0 0 24 24" |  | ||||||
|             stroke-linecap="round" |  | ||||||
|             stroke-linejoin="round" |  | ||||||
|             class="stroke-current text-xl text-facebook" |  | ||||||
|             height="1em" |  | ||||||
|             width="1em" |  | ||||||
|             xmlns="http://www.w3.org/2000/svg" |  | ||||||
|             ><path |  | ||||||
|               d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z" |  | ||||||
|             /></svg |  | ||||||
|           ><svg |  | ||||||
|             stroke="currentColor" |  | ||||||
|             fill="none" |  | ||||||
|             stroke-width="2" |  | ||||||
|             viewBox="0 0 24 24" |  | ||||||
|             stroke-linecap="round" |  | ||||||
|             stroke-linejoin="round" |  | ||||||
|             class="stroke-current text-xl text-instagram" |  | ||||||
|             height="1em" |  | ||||||
|             width="1em" |  | ||||||
|             xmlns="http://www.w3.org/2000/svg" |  | ||||||
|             ><rect x="2" y="2" width="20" height="20" rx="5" ry="5" /> |  | ||||||
|             <path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" /> |  | ||||||
|             <line x1="17.5" y1="6.5" x2="17.5" y2="6.5" /></svg |  | ||||||
|           > |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|       <div class="ml-auto flex-shrink-0 space-x-2 hidden lg:flex"> |  | ||||||
|         <button |  | ||||||
|           class="btn btn-default btn-rounded bg-blue-500 hover:bg-blue-600 text-white" |  | ||||||
|           >Subscribe</button |  | ||||||
|         ><button |  | ||||||
|           class="btn btn-default btn-rounded bg-blue-500 hover:bg-blue-600 text-white" |  | ||||||
|           >Follow</button |  | ||||||
|         > |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|     <div class="flex flex-wrap"> |  | ||||||
|       <div class="w-full p-4"> |  | ||||||
|         <div class="flex flex-wrap flex-col w-full tabs"> |  | ||||||
|           <div class="flex lg:flex-wrap flex-row lg:space-x-2"> |  | ||||||
|             <div class="flex-none"> |  | ||||||
|               <button class="tab tab-underline tab-active" type="button" |  | ||||||
|                 >Account settings</button |  | ||||||
|               > |  | ||||||
|             </div> |  | ||||||
|             <div class="flex-none"> |  | ||||||
|               <button class="tab tab-underline" type="button" |  | ||||||
|                 >Email preferences</button |  | ||||||
|               > |  | ||||||
|             </div> |  | ||||||
|             <div class="flex-none"> |  | ||||||
|               <button class="tab tab-underline" type="button" |  | ||||||
|                 >Security settings</button |  | ||||||
|               > |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|           <div class="tab-content block"> |  | ||||||
|             <div class="py-4 w-full lg:w-1/2"> |  | ||||||
|               <div class="flex flex-col"> |  | ||||||
|                 <form class="form flex flex-wrap w-full"> |  | ||||||
|                   <div class="w-full"> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">First name</div> |  | ||||||
|                       <input |  | ||||||
|                         name="first-name" |  | ||||||
|                         type="text" |  | ||||||
|                         class="form-input" |  | ||||||
|                         placeholder="Enter you first name" |  | ||||||
|                       /> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">Last name</div> |  | ||||||
|                       <input |  | ||||||
|                         name="last-name" |  | ||||||
|                         type="text" |  | ||||||
|                         class="form-input" |  | ||||||
|                         placeholder="Enter you last name" |  | ||||||
|                       /> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">Email address</div> |  | ||||||
|                       <input |  | ||||||
|                         name="email" |  | ||||||
|                         type="email" |  | ||||||
|                         class="form-input" |  | ||||||
|                         placeholder="Enter you email address" |  | ||||||
|                       /> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">Company</div> |  | ||||||
|                       <input |  | ||||||
|                         name="company" |  | ||||||
|                         type="text" |  | ||||||
|                         class="form-input" |  | ||||||
|                         placeholder="Enter you company" |  | ||||||
|                       /> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">Position</div> |  | ||||||
|                       <input |  | ||||||
|                         name="position" |  | ||||||
|                         type="text" |  | ||||||
|                         class="form-input" |  | ||||||
|                         placeholder="Enter you position" |  | ||||||
|                       /> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">Language</div> |  | ||||||
|                       <select name="language" class="form-select" |  | ||||||
|                         ><option>Select language</option> |  | ||||||
|                         <option value="english">English</option> |  | ||||||
|                         <option value="spanish">Spanish</option> |  | ||||||
|                         <option value="portuguese">Portuguese</option></select |  | ||||||
|                       > |  | ||||||
|                     </div> |  | ||||||
|                   </div> |  | ||||||
|                   <input |  | ||||||
|                     type="submit" |  | ||||||
|                     class="btn btn-default bg-blue-500 hover:bg-blue-600 text-white btn-rounded" |  | ||||||
|                   /> |  | ||||||
|                 </form> |  | ||||||
|               </div> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|           <div class="tab-content hidden"> |  | ||||||
|             <div class="py-4 w-full lg:w-1/2"> |  | ||||||
|               <div class="flex flex-col"> |  | ||||||
|                 <form class="form flex flex-wrap w-full"> |  | ||||||
|                   <div class="w-full"> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">Current email</div> |  | ||||||
|                       <input |  | ||||||
|                         name="email" |  | ||||||
|                         type="email" |  | ||||||
|                         class="form-input" |  | ||||||
|                         placeholder="Enter you current email address" |  | ||||||
|                       /> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">New email</div> |  | ||||||
|                       <input |  | ||||||
|                         name="email" |  | ||||||
|                         type="email" |  | ||||||
|                         class="form-input" |  | ||||||
|                         placeholder="Enter you new email address" |  | ||||||
|                       /> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">Daily updates</div> |  | ||||||
|                       <div class="flex items-center justify-start space-x-2"> |  | ||||||
|                         <label class="flex items-center justify-start space-x-2" |  | ||||||
|                           ><input |  | ||||||
|                             type="radio" |  | ||||||
|                             name="daily-updates" |  | ||||||
|                             class="form-radio h-4 w-4" |  | ||||||
|                             value="yes" |  | ||||||
|                           /><span class="">Yes</span></label |  | ||||||
|                         ><label |  | ||||||
|                           class="flex items-center justify-start space-x-2" |  | ||||||
|                           ><input |  | ||||||
|                             type="radio" |  | ||||||
|                             name="daily-updates" |  | ||||||
|                             class="form-radio h-4 w-4" |  | ||||||
|                             value="no" |  | ||||||
|                           /><span class="">No</span></label |  | ||||||
|                         > |  | ||||||
|                       </div> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">Weekly updates</div> |  | ||||||
|                       <div class="flex items-center justify-start space-x-2"> |  | ||||||
|                         <label class="flex items-center justify-start space-x-2" |  | ||||||
|                           ><input |  | ||||||
|                             type="radio" |  | ||||||
|                             name="weekle-updates" |  | ||||||
|                             class="form-radio h-4 w-4" |  | ||||||
|                             value="yes" |  | ||||||
|                           /><span class="">Yes</span></label |  | ||||||
|                         ><label |  | ||||||
|                           class="flex items-center justify-start space-x-2" |  | ||||||
|                           ><input |  | ||||||
|                             type="radio" |  | ||||||
|                             name="weekle-updates" |  | ||||||
|                             class="form-radio h-4 w-4" |  | ||||||
|                             value="no" |  | ||||||
|                           /><span class="">No</span></label |  | ||||||
|                         > |  | ||||||
|                       </div> |  | ||||||
|                     </div> |  | ||||||
|                   </div> |  | ||||||
|                   <input |  | ||||||
|                     type="submit" |  | ||||||
|                     class="btn btn-default bg-blue-500 hover:bg-blue-600 text-white btn-rounded" |  | ||||||
|                   /> |  | ||||||
|                 </form> |  | ||||||
|               </div> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|           <div class="tab-content hidden"> |  | ||||||
|             <div class="py-4 w-full lg:w-1/2"> |  | ||||||
|               <div class="flex flex-col"> |  | ||||||
|                 <form class="form flex flex-wrap w-full"> |  | ||||||
|                   <div class="w-full"> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">Current password</div> |  | ||||||
|                       <input |  | ||||||
|                         name="current-password" |  | ||||||
|                         type="password" |  | ||||||
|                         class="form-input" |  | ||||||
|                         placeholder="Enter your current password" |  | ||||||
|                       /> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">New password</div> |  | ||||||
|                       <input |  | ||||||
|                         name="new-password" |  | ||||||
|                         type="password" |  | ||||||
|                         class="form-input" |  | ||||||
|                         placeholder="Enter your new password" |  | ||||||
|                       /> |  | ||||||
|                     </div> |  | ||||||
|                     <div class="form-element"> |  | ||||||
|                       <div class="form-label">Confirm new password</div> |  | ||||||
|                       <input |  | ||||||
|                         name="confirm-new-password" |  | ||||||
|                         type="password" |  | ||||||
|                         class="form-input" |  | ||||||
|                         placeholder="Enter your new password confirmation" |  | ||||||
|                       /> |  | ||||||
|                     </div> |  | ||||||
|                   </div> |  | ||||||
|                   <input |  | ||||||
|                     type="submit" |  | ||||||
|                     class="btn btn-default bg-blue-500 hover:bg-blue-600 text-white btn-rounded" |  | ||||||
|                   /> |  | ||||||
|                 </form> |  | ||||||
|               </div> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </div> |  | ||||||
| @@ -1,92 +0,0 @@ | |||||||
| <!-- This example requires Tailwind CSS v2.0+ --> |  | ||||||
| <div class="flex flex-col"> |  | ||||||
|   <div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8"> |  | ||||||
|     <div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8"> |  | ||||||
|       <div |  | ||||||
|         class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg" |  | ||||||
|       > |  | ||||||
|         <table class="min-w-full divide-y divide-gray-200"> |  | ||||||
|           <thead class="bg-gray-50"> |  | ||||||
|             <tr class="odd:bg-white even:bg-gray-100"> |  | ||||||
|               <th |  | ||||||
|                 scope="col" |  | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" |  | ||||||
|               > |  | ||||||
|                 Name |  | ||||||
|               </th> |  | ||||||
|               <th |  | ||||||
|                 scope="col" |  | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" |  | ||||||
|               > |  | ||||||
|                 Title |  | ||||||
|               </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="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" |  | ||||||
|               > |  | ||||||
|                 Role |  | ||||||
|               </th> |  | ||||||
|               <th scope="col" class="relative px-6 py-3"> |  | ||||||
|                 <span class="sr-only">{$_("edit")}</span> |  | ||||||
|               </th> |  | ||||||
|             </tr> |  | ||||||
|           </thead> |  | ||||||
|           <tbody class="divide-y divide-gray-200"> |  | ||||||
|             <tr class="odd:bg-white even:bg-gray-100"> |  | ||||||
|               <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                 <div class="flex items-center"> |  | ||||||
|                   <div class="flex-shrink-0 h-10 w-10"> |  | ||||||
|                     <img |  | ||||||
|                       class="h-10 w-10 rounded-full" |  | ||||||
|                       src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=4&w=256&h=256&q=60" |  | ||||||
|                       alt="" |  | ||||||
|                     /> |  | ||||||
|                   </div> |  | ||||||
|                   <div class="ml-4"> |  | ||||||
|                     <div class="text-sm font-medium text-gray-900"> |  | ||||||
|                       Jane Cooper |  | ||||||
|                     </div> |  | ||||||
|                     <div class="text-sm text-gray-500"> |  | ||||||
|                       jane.cooper@example.com |  | ||||||
|                     </div> |  | ||||||
|                   </div> |  | ||||||
|                 </div> |  | ||||||
|               </td> |  | ||||||
|               <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                 <div class="text-sm text-gray-900"> |  | ||||||
|                   Regional Paradigm Technician |  | ||||||
|                 </div> |  | ||||||
|                 <div class="text-sm text-gray-500">Optimization</div> |  | ||||||
|               </td> |  | ||||||
|               <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                 <span |  | ||||||
|                   class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800" |  | ||||||
|                 > |  | ||||||
|                   Active |  | ||||||
|                 </span> |  | ||||||
|               </td> |  | ||||||
|               <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> |  | ||||||
|                 Admin |  | ||||||
|               </td> |  | ||||||
|               <td |  | ||||||
|                 class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium" |  | ||||||
|               > |  | ||||||
|                 <a href="#" class="text-indigo-600 hover:text-indigo-900" |  | ||||||
|                   >{$_("edit")}</a |  | ||||||
|                 > |  | ||||||
|               </td> |  | ||||||
|             </tr> |  | ||||||
|  |  | ||||||
|             <!-- More rows... --> |  | ||||||
|           </tbody> |  | ||||||
|         </table> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </div> |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| <h3 class="text-lg">Tabs</h3> |  | ||||||
| <div |  | ||||||
|   class="w-full flex sm:border-b sm:border-gray-300 relative flex-col sm:flex-row" |  | ||||||
| > |  | ||||||
|   <div |  | ||||||
|     class="flex-1 sm:text-center font-medium pb-3 cursor-pointer hover:text-blue-400 false" |  | ||||||
|   > |  | ||||||
|     1 |  | ||||||
|   </div> |  | ||||||
|   <div |  | ||||||
|     class="flex-1 sm:text-center font-medium pb-3 cursor-pointer hover:text-blue-400 false" |  | ||||||
|   > |  | ||||||
|     2 |  | ||||||
|   </div> |  | ||||||
|   <div |  | ||||||
|     class="flex-1 sm:text-center font-medium pb-3 cursor-pointer hover:text-blue-400 false" |  | ||||||
|   > |  | ||||||
|     3 |  | ||||||
|   </div> |  | ||||||
|   <div |  | ||||||
|     class="hidden sm:block absolute bottom-0 left-0 h-1 bg-blue-400 transition-transform duration-300 ease-out w-1/4 transform translate-x-double" |  | ||||||
|   /> |  | ||||||
| </div> |  | ||||||
| @@ -1,113 +0,0 @@ | |||||||
| <div> |  | ||||||
|   <div |  | ||||||
|     class="text-xs inline-flex items-center font-bold leading-sm uppercase px-3 py-1 bg-blue-200 text-blue-700 rounded-full" |  | ||||||
|   > |  | ||||||
|     <svg |  | ||||||
|       xmlns="http://www.w3.org/2000/svg" |  | ||||||
|       width="16" |  | ||||||
|       height="16" |  | ||||||
|       viewBox="0 0 24 24" |  | ||||||
|       fill="none" |  | ||||||
|       stroke="currentColor" |  | ||||||
|       stroke-width="2" |  | ||||||
|       stroke-linecap="round" |  | ||||||
|       stroke-linejoin="round" |  | ||||||
|       class="feather feather-bell-off mr-2" |  | ||||||
|     > |  | ||||||
|       <path d="M13.73 21a2 2 0 0 1-3.46 0" /> |  | ||||||
|       <path d="M18.63 13A17.89 17.89 0 0 1 18 8" /> |  | ||||||
|       <path d="M6.26 6.26A5.86 5.86 0 0 0 6 8c0 7-3 9-3 9h14" /> |  | ||||||
|       <path d="M18 8a6 6 0 0 0-9.33-5" /> |  | ||||||
|       <line x1="1" y1="1" x2="23" y2="23" /> |  | ||||||
|     </svg> |  | ||||||
|     Tag |  | ||||||
|   </div> |  | ||||||
|  |  | ||||||
|   <div |  | ||||||
|     class="ml-4 text-xs inline-flex items-center font-bold leading-sm uppercase px-3 py-1 bg-green-200 text-green-700 rounded-full" |  | ||||||
|   > |  | ||||||
|     <svg |  | ||||||
|       xmlns="http://www.w3.org/2000/svg" |  | ||||||
|       width="16" |  | ||||||
|       height="16" |  | ||||||
|       viewBox="0 0 24 24" |  | ||||||
|       fill="none" |  | ||||||
|       stroke="currentColor" |  | ||||||
|       stroke-width="2" |  | ||||||
|       stroke-linecap="round" |  | ||||||
|       stroke-linejoin="round" |  | ||||||
|       class="feather feather-arrow-right mr-2" |  | ||||||
|     > |  | ||||||
|       <line x1="5" y1="12" x2="19" y2="12" /> |  | ||||||
|       <polyline points="12 5 19 12 12 19" /> |  | ||||||
|     </svg> |  | ||||||
|     Tag |  | ||||||
|   </div> |  | ||||||
|  |  | ||||||
|   <div |  | ||||||
|     class="ml-4 text-xs inline-flex items-center font-bold leading-sm uppercase px-3 py-1 bg-orange-200 text-orange-700 rounded-full" |  | ||||||
|   > |  | ||||||
|     <svg |  | ||||||
|       xmlns="http://www.w3.org/2000/svg" |  | ||||||
|       width="16" |  | ||||||
|       height="16" |  | ||||||
|       viewBox="0 0 24 24" |  | ||||||
|       fill="none" |  | ||||||
|       stroke="currentColor" |  | ||||||
|       stroke-width="2" |  | ||||||
|       stroke-linecap="round" |  | ||||||
|       stroke-linejoin="round" |  | ||||||
|       class="feather feather-activity mr-2" |  | ||||||
|     > |  | ||||||
|       <polyline points="22 12 18 12 15 21 9 3 6 12 2 12" /> |  | ||||||
|     </svg> |  | ||||||
|     Tag |  | ||||||
|   </div> |  | ||||||
|  |  | ||||||
|   <div |  | ||||||
|     class="ml-4 text-xs inline-flex items-center font-bold leading-sm uppercase px-3 py-1 bg-red-200 text-red-700 rounded-full" |  | ||||||
|   > |  | ||||||
|     <svg |  | ||||||
|       xmlns="http://www.w3.org/2000/svg" |  | ||||||
|       width="16" |  | ||||||
|       height="16" |  | ||||||
|       viewBox="0 0 24 24" |  | ||||||
|       fill="none" |  | ||||||
|       stroke="currentColor" |  | ||||||
|       stroke-width="2" |  | ||||||
|       stroke-linecap="round" |  | ||||||
|       stroke-linejoin="round" |  | ||||||
|       class="feather feather-archive mr-2" |  | ||||||
|     > |  | ||||||
|       <polyline points="21 8 21 21 3 21 3 8" /> |  | ||||||
|       <rect x="1" y="3" width="22" height="5" /> |  | ||||||
|       <line x1="10" y1="12" x2="14" y2="12" /> |  | ||||||
|     </svg> |  | ||||||
|     Tag |  | ||||||
|   </div> |  | ||||||
|  |  | ||||||
|   <div |  | ||||||
|     class="ml-4 text-xs inline-flex items-center font-bold leading-sm uppercase px-3 py-1 rounded-full bg-white text-gray-700 border" |  | ||||||
|   > |  | ||||||
|     <svg |  | ||||||
|       xmlns="http://www.w3.org/2000/svg" |  | ||||||
|       width="16" |  | ||||||
|       height="16" |  | ||||||
|       viewBox="0 0 24 24" |  | ||||||
|       fill="none" |  | ||||||
|       stroke="currentColor" |  | ||||||
|       stroke-width="2" |  | ||||||
|       stroke-linecap="round" |  | ||||||
|       stroke-linejoin="round" |  | ||||||
|       class="feather feather-hard-drive mr-2" |  | ||||||
|     > |  | ||||||
|       <line x1="22" y1="12" x2="2" y2="12" /> |  | ||||||
|       <path |  | ||||||
|         d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" |  | ||||||
|       /> |  | ||||||
|       <line x1="6" y1="16" x2="6.01" y2="16" /> |  | ||||||
|       <line x1="10" y1="16" x2="10.01" y2="16" /> |  | ||||||
|     </svg> |  | ||||||
|     Tag |  | ||||||
|   </div> |  | ||||||
| </div> |  | ||||||
| @@ -12,6 +12,7 @@ | |||||||
|   import Select from "svelte-select"; |   import Select from "svelte-select"; | ||||||
|   import { createEventDispatcher } from "svelte"; |   import { createEventDispatcher } from "svelte"; | ||||||
|   const dispatch = createEventDispatcher(); |   const dispatch = createEventDispatcher(); | ||||||
|  |   import toast from 'svelte-french-toast' | ||||||
|  |  | ||||||
|   export let modal_open; |   export let modal_open; | ||||||
|   $: selected_team = undefined; |   $: selected_team = undefined; | ||||||
| @@ -116,14 +117,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -136,15 +137,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 xmlns="http://www.w3.org/2000/svg" |                 xmlns="http://www.w3.org/2000/svg" | ||||||
| @@ -159,18 +160,18 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("create-a-new-runner")} |                 {$_("create-a-new-runner")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "please-provide-the-required-information-to-add-a-new-runner" |                     "please-provide-the-required-information-to-add-a-new-runner" | ||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="firstname" |                     for="firstname" | ||||||
| @@ -188,7 +189,7 @@ | |||||||
|                     bind:this={firstname_input} |                     bind:this={firstname_input} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="firstname" |                     name="firstname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isFirstnameValid} |                   {#if !isFirstnameValid} | ||||||
|                     <span |                     <span | ||||||
| @@ -211,7 +212,7 @@ | |||||||
|                     bind:this={middlename_input} |                     bind:this={middlename_input} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="trackname" |                     name="trackname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
| @@ -230,7 +231,7 @@ | |||||||
|                     bind:this={lastname_input} |                     bind:this={lastname_input} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="lastname" |                     name="lastname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isLastnameValid} |                   {#if !isLastnameValid} | ||||||
|                     <span |                     <span | ||||||
| @@ -247,7 +248,7 @@ | |||||||
|                     >{$_("team")}</label |                     >{$_("team")}</label | ||||||
|                   > |                   > | ||||||
|                   <Select |                   <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" |                     containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     itemFilter={(label, filterText, option) => |                     itemFilter={(label, filterText, option) => | ||||||
|                       label.toLowerCase().includes(filterText.toLowerCase()) || |                       label.toLowerCase().includes(filterText.toLowerCase()) || | ||||||
|                       option.value.id |                       option.value.id | ||||||
| @@ -280,7 +281,7 @@ | |||||||
|                     bind:this={phone_input} |                     bind:this={phone_input} | ||||||
|                     type="tel" |                     type="tel" | ||||||
|                     name="phone" |                     name="phone" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isPhoneValidOrEmpty} |                   {#if !isPhoneValidOrEmpty} | ||||||
|                     <span |                     <span | ||||||
| @@ -308,7 +309,7 @@ | |||||||
|                     bind:this={email_input} |                     bind:this={email_input} | ||||||
|                     type="email" |                     type="email" | ||||||
|                     name="email" |                     name="email" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                   {#if !isEmailValidOrEmpty} |                   {#if !isEmailValidOrEmpty} | ||||||
|                     <span |                     <span | ||||||
| @@ -322,13 +323,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("create")} |             {$_("create")} | ||||||
|           </button> |           </button> | ||||||
| @@ -337,7 +338,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -31,14 +31,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -51,15 +51,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 xmlns="http://www.w3.org/2000/svg" |                 xmlns="http://www.w3.org/2000/svg" | ||||||
| @@ -74,15 +74,10 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("confirm-delete")} |                 {$_('delete_runner')} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |  | ||||||
|                 <p class="text-sm text-gray-500"> |  | ||||||
|                   {$_("please-confirm-the-deletion-of-runner")} |  | ||||||
|                 </p> |  | ||||||
|               </div> |  | ||||||
|               <div class="w-full"> |               <div class="w-full"> | ||||||
|                 <span class="inline-block" |                 <span class="inline-block" | ||||||
|                   >{delete_runner.firstname} {delete_runner.lastname}</span |                   >{delete_runner.firstname} {delete_runner.lastname}</span | ||||||
| @@ -91,11 +86,11 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-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" | ||||||
|           > |           > | ||||||
|             {$_("delete")} |             {$_("delete")} | ||||||
|           </button> |           </button> | ||||||
| @@ -104,7 +99,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -1,401 +1,386 @@ | |||||||
| <script> | <script> | ||||||
|   import csv from "csvtojson"; | 	import csv from "csvtojson"; | ||||||
|   import { read as readXlsx, utils as xlsx_utils } from "xlsx"; | 	import { read as readXlsx, utils as xlsx_utils } from "xlsx"; | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import { clickOutside } from "../base/outsideclick"; | 	import { clickOutside } from "../base/outsideclick"; | ||||||
|  |  | ||||||
|   import { | 	import { | ||||||
|     ImportService, | 		ImportService, | ||||||
|     RunnerTeamService, | 		RunnerTeamService, | ||||||
|     RunnerOrganizationService, | 		RunnerOrganizationService, | ||||||
|   } from "@odit/lfk-client-js"; | 	} from "@odit/lfk-client-js"; | ||||||
|   import { createEventDispatcher } from "svelte"; | 	import { createEventDispatcher } from "svelte"; | ||||||
|   import Select from "svelte-select"; | 	import Select from "svelte-select"; | ||||||
|   import toast from "svelte-french-toast"; | 	import toast from "svelte-french-toast"; | ||||||
|   export let opened_from; | 	export let opened_from; | ||||||
|   export let passed_org; | 	export let passed_org; | ||||||
|   export let passed_orgs; | 	export let passed_orgs; | ||||||
|   export let passed_team; | 	export let passed_team; | ||||||
|   export let import_modal_open; | 	export let import_modal_open; | ||||||
|   $: searchvalue = ""; | 	$: searchvalue = ""; | ||||||
|   $: importButtonEnabled = | 	$: importButtonEnabled = | ||||||
|     recent_processed && | 		recent_processed && | ||||||
|     (!(selected_org_or_team == "" || selected_org_or_team == null) || | 		(!(selected_org_or_team == "" || selected_org_or_team == null) || | ||||||
|       !(passed_org?.id == null || passed_org?.id == 0) || | 			!(passed_org?.id == null || passed_org?.id == 0) || | ||||||
|       !(passed_team?.id == null || passed_team?.id == 0)); | 			!(passed_team?.id == null || passed_team?.id == 0)); | ||||||
|   const dispatch = createEventDispatcher(); | 	const dispatch = createEventDispatcher(); | ||||||
|   function cancelModal() { | 	function cancelModal() { | ||||||
|     json_output = []; | 		json_output = []; | ||||||
|     import_modal_open = false; | 		import_modal_open = false; | ||||||
|     dispatch("cancel"); | 		dispatch("cancel"); | ||||||
|   } | 	} | ||||||
|   (() => { | 	(() => { | ||||||
|     document.onkeydown = (e) => { | 		document.onkeydown = (e) => { | ||||||
|       e = e || window.event; | 			e = e || window.event; | ||||||
|       if (e.key === "Escape") { | 			if (e.key === "Escape") { | ||||||
|         cancelModal(); | 				cancelModal(); | ||||||
|       } | 			} | ||||||
|       if (e.keyCode === 13) { | 			if (e.keyCode === 13) { | ||||||
|         // | 				// | ||||||
|       } | 			} | ||||||
|     }; | 		}; | ||||||
|   })(); | 	})(); | ||||||
|   let groups = []; | 	let groups = []; | ||||||
|   RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => { | 	RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => { | ||||||
|     const orgs = val.map((r) => { | 		const orgs = val.map((r) => { | ||||||
|       return { label: r.name, value: `ORG_${r.id}` }; | 			return { label: r.name, value: `ORG_${r.id}` }; | ||||||
|     }); | 		}); | ||||||
|     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 { | 				return { | ||||||
|           label: `${r.parentGroup.name} > ${r.name}`, | 					label: `${r.parentGroup.name} > ${r.name}`, | ||||||
|           value: `TEAM_${r.id}`, | 					value: `TEAM_${r.id}`, | ||||||
|         }; | 				}; | ||||||
|       }); | 			}); | ||||||
|       groups = groups.concat(teams); | 			groups = groups.concat(teams); | ||||||
|     }); | 		}); | ||||||
|   }); | 	}); | ||||||
|   let selected_org; | 	let selected_org; | ||||||
|   $: selected_org_or_team = ""; | 	$: selected_org_or_team = ""; | ||||||
|   let files; | 	let files; | ||||||
|   let recent_processed = true; | 	let recent_processed = true; | ||||||
|   $: json_output = []; | 	$: json_output = []; | ||||||
|   $: { | 	$: { | ||||||
|     if (files) { | 		if (files) { | ||||||
|       if ( | 			if ( | ||||||
|         files[0].type === | 				files[0].type === | ||||||
|         "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | 				"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | ||||||
|       ) { | 			) { | ||||||
|         const reader = new FileReader(); | 				const reader = new FileReader(); | ||||||
|         reader.addEventListener("load", async (e) => { | 				reader.addEventListener("load", async (e) => { | ||||||
|           const data = new Uint8Array(e.target.result); | 					const data = new Uint8Array(e.target.result); | ||||||
|           const out = readXlsx(data, { type: "array" }); | 					const out = readXlsx(data, { type: "array" }); | ||||||
|           json_output = xlsx_utils.sheet_to_json( | 					json_output = xlsx_utils.sheet_to_json( | ||||||
|             out.Sheets[Object.keys(out.Sheets)[0]] | 						out.Sheets[Object.keys(out.Sheets)[0]] | ||||||
|           ); | 					); | ||||||
|         }); | 				}); | ||||||
|         reader.readAsArrayBuffer(files[0]); | 				reader.readAsArrayBuffer(files[0]); | ||||||
|       } else { | 			} else { | ||||||
|         const reader = new FileReader(); | 				const reader = new FileReader(); | ||||||
|         reader.addEventListener("load", async (e) => { | 				reader.addEventListener("load", async (e) => { | ||||||
|           json_output = await csv({ | 					json_output = await csv({ | ||||||
|             delimiter: [";", ","], | 						delimiter: [";", ","], | ||||||
|             trim: true, | 						trim: true, | ||||||
|           }).fromString(e.target.result); | 					}).fromString(e.target.result); | ||||||
|         }); | 				}); | ||||||
|         reader.readAsText(files[0]); | 				reader.readAsText(files[0]); | ||||||
|       } | 			} | ||||||
|     } | 		} | ||||||
|   } | 	} | ||||||
|   function importAction() { | 	function importAction() { | ||||||
|     if (recent_processed === true) { | 		if (recent_processed === true) { | ||||||
|       toast.loading($_("runners-are-being-imported")); | 			toast.loading($_("runners-are-being-imported")); | ||||||
|       recent_processed = false; | 			recent_processed = false; | ||||||
|       const mapped = json_output.map(function (runner) { | 			const mapped = json_output.map(function (runner) { | ||||||
|         return { | 				return { | ||||||
|           firstname: runner[`${$_("csv_import__firstname")}`], | 					firstname: runner[`${$_("csv_import__firstname")}`], | ||||||
|           middlename: runner[`${$_("csv_import__middlename")}`], | 					middlename: runner[`${$_("csv_import__middlename")}`], | ||||||
|           lastname: runner[`${$_("csv_import__lastname")}`], | 					lastname: runner[`${$_("csv_import__lastname")}`], | ||||||
|           team: | 					team: | ||||||
|             runner[`${$_("csv_import__team")}`] || | 						runner[`${$_("csv_import__team")}`] || | ||||||
|             runner[`${$_("csv_import__class")}`], | 						runner[`${$_("csv_import__class")}`], | ||||||
|         }; | 				}; | ||||||
|       }); | 			}); | ||||||
|       let org = 0; | 			let org = 0; | ||||||
|       if (opened_from === "OrgDetail") { | 			if (opened_from === "OrgDetail") { | ||||||
|         org = passed_org.id; | 				org = passed_org.id; | ||||||
|       } | 			} | ||||||
|       if (opened_from === "OrgOverview") { | 			if (opened_from === "OrgOverview") { | ||||||
|         org = parseInt(selected_org); | 				org = parseInt(selected_org); | ||||||
|       } | 			} | ||||||
|       if (opened_from === "OrgOverview" || opened_from === "OrgDetail") { | 			if (opened_from === "OrgOverview" || opened_from === "OrgDetail") { | ||||||
|         ImportService.importControllerPostOrgsJson(org, mapped) | 				ImportService.importControllerPostOrgsJson(org, mapped) | ||||||
|           .then((resp) => { | 					.then((resp) => { | ||||||
|             toast.dismiss(); | 						toast.dismiss(); | ||||||
|             recent_processed = true; | 						recent_processed = true; | ||||||
|             toast.success($_("import-finished")); | 						toast.success($_("import-finished")); | ||||||
|             cancelModal(); | 						cancelModal(); | ||||||
|           }) | 					}) | ||||||
|           .catch((err) => { | 					.catch((err) => { | ||||||
|             toast.dismiss(); | 						toast.dismiss(); | ||||||
|             recent_processed = true; | 						recent_processed = true; | ||||||
|             toast.error($_("error-during-import")); | 						toast.error($_("error-during-import")); | ||||||
|             cancelModal(); | 						cancelModal(); | ||||||
|           }); | 					}); | ||||||
|       } | 			} | ||||||
|       if (opened_from === "TeamDetail") { | 			if (opened_from === "TeamDetail") { | ||||||
|         ImportService.importControllerPostTeamsJson(passed_team.id, mapped) | 				ImportService.importControllerPostTeamsJson(passed_team.id, mapped) | ||||||
|           .then((resp) => { | 					.then((resp) => { | ||||||
|             toast.dismiss(); | 						toast.dismiss(); | ||||||
|             recent_processed = true; | 						recent_processed = true; | ||||||
|             toast.success($_("import-finished")); | 						toast.success($_("import-finished")); | ||||||
|             cancelModal(); | 						cancelModal(); | ||||||
|           }) | 					}) | ||||||
|           .catch((err) => { | 					.catch((err) => { | ||||||
|             toast.dismiss(); | 						toast.dismiss(); | ||||||
|             recent_processed = true; | 						recent_processed = true; | ||||||
|             toast.error($_("error-during-import")); | 						toast.error($_("error-during-import")); | ||||||
|             cancelModal(); | 						cancelModal(); | ||||||
|           }); | 					}); | ||||||
|       } | 			} | ||||||
|       if (opened_from === "RunnerOverview") { | 			if (opened_from === "RunnerOverview") { | ||||||
|         if (selected_org_or_team.includes("ORG_")) { | 				if (selected_org_or_team.includes("ORG_")) { | ||||||
|           selected_org_or_team = selected_org_or_team.split("_")[1]; | 					selected_org_or_team = selected_org_or_team.split("_")[1]; | ||||||
|           ImportService.importControllerPostOrgsJson( | 					ImportService.importControllerPostOrgsJson( | ||||||
|             selected_org_or_team, | 						selected_org_or_team, | ||||||
|             mapped | 						mapped | ||||||
|           ) | 					) | ||||||
|             .then((resp) => { | 						.then((resp) => { | ||||||
|               dispatch("created", { runners: resp }); | 							dispatch("created", { runners: resp }); | ||||||
|               toast.dismiss(); | 							toast.dismiss(); | ||||||
|               recent_processed = true; | 							recent_processed = true; | ||||||
|               toast($_("import-finished")); | 							toast.success($_("import-finished")); | ||||||
|               cancelModal(); | 							cancelModal(); | ||||||
|             }) | 						}) | ||||||
|             .catch((err) => { | 						.catch((err) => { | ||||||
|               toast.dismiss(); | 							toast.dismiss(); | ||||||
|               recent_processed = true; | 							recent_processed = true; | ||||||
|               toast.error($_("error-during-import")); | 							toast.error($_("error-during-import")); | ||||||
|               cancelModal(); | 							cancelModal(); | ||||||
|             }); | 						}); | ||||||
|         } | 				} | ||||||
|         if (selected_org_or_team.includes("TEAM_")) { | 				if (selected_org_or_team.includes("TEAM_")) { | ||||||
|           selected_org_or_team = selected_org_or_team.split("_")[1]; | 					selected_org_or_team = selected_org_or_team.split("_")[1]; | ||||||
|           ImportService.importControllerPostTeamsJson( | 					ImportService.importControllerPostTeamsJson( | ||||||
|             selected_org_or_team, | 						selected_org_or_team, | ||||||
|             mapped | 						mapped | ||||||
|           ) | 					) | ||||||
|             .then((resp) => { | 						.then((resp) => { | ||||||
|               dispatch("created", { runners: resp }); | 							dispatch("created", { runners: resp }); | ||||||
|               toast.dismiss(); | 							toast.dismiss(); | ||||||
|               recent_processed = true; | 							recent_processed = true; | ||||||
|               toast($_("import-finished")); | 							toast.success($_("import-finished")); | ||||||
|               cancelModal(); | 							cancelModal(); | ||||||
|             }) | 						}) | ||||||
|             .catch((err) => { | 						.catch((err) => { | ||||||
|               toast.dismiss(); | 							toast.dismiss(); | ||||||
|               recent_processed = true; | 							recent_processed = true; | ||||||
|               toast.error($_("error-during-import")); | 							toast.error($_("error-during-import")); | ||||||
|               cancelModal(); | 							cancelModal(); | ||||||
|             }); | 						}); | ||||||
|         } | 				} | ||||||
|       } | 			} | ||||||
|     } | 		} | ||||||
|   } | 	} | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if import_modal_open} | {#if import_modal_open} | ||||||
|   <div | 	<div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" | 		class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside | 		use:clickOutside | ||||||
|     on:click_outside={() => { | 		on:click_outside={() => { | ||||||
|       cancelModal(); | 			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 h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > | 		> | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | 			<div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div | 				<div | ||||||
|           class="absolute inset-0 bg-gray-500 opacity-75" | 					class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|           data-id="modal_backdrop" | 					data-id="modal_backdrop" | ||||||
|         /> | 				/> | ||||||
|       </div> | 			</div> | ||||||
|       <span | 			<span | ||||||
|         class="hidden sm:inline-block sm:align-middle sm:h-screen" | 				class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|         aria-hidden="true">​</span | 				aria-hidden="true">​</span | ||||||
|       > | 			> | ||||||
|       <div | 			<div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-max sm:w-full" | 				class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" | 				role="dialog" | ||||||
|         aria-modal="true" | 				aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" | 				aria-labelledby="modal-headline" | ||||||
|       > | 			> | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> | 				<div | ||||||
|           <div class="sm:flex sm:items-start"> | 					class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl lg:rounded-xl" | ||||||
|             <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" | 					<div class=""> | ||||||
|             > | 						<div | ||||||
|               <svg | 							class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 						> | ||||||
|                 viewBox="0 0 24 24" | 							<svg | ||||||
|                 class="h-6 w-6 text-blue-600" | 								xmlns="http://www.w3.org/2000/svg" | ||||||
|                 fill="currentColor" | 								viewBox="0 0 24 24" | ||||||
|                 width="24" | 								class="h-6 w-6 text-blue-600" | ||||||
|                 height="24" | 								fill="currentColor" | ||||||
|                 ><path fill="none" d="M0 0h24v24H0z" /> | 								width="24" | ||||||
|                 <path | 								height="24" | ||||||
|                   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" | 								><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|                 /></svg | 								<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" | ||||||
|             </div> | 								/></svg | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-2 sm:text-left w-full"> | 							> | ||||||
|               <h3 class="text-lg leading-6 font-bold mt-2 text-gray-900"> | 						</div> | ||||||
|                 {$_("runner-import")} | 						<div class="mt-3 sm:mt-0 sm:text-left w-full"> | ||||||
|               </h3> | 							<h3 class="text-lg leading-6 font-bold mt-2 text-gray-900"> | ||||||
|             </div> | 								{$_("runner-import")} | ||||||
|           </div> | 							</h3> | ||||||
|           <div class="mt-5 text-center sm:mt-0 sm:ml-2 sm:text-left w-full"> | 						</div> | ||||||
|             {#if json_output.length === 0} | 					</div> | ||||||
|               <div class="mt-2 mb-6"> | 					<div class="sm:text-left w-full"> | ||||||
|                 <p class="text-sm text-gray-500"> | 						{#if json_output.length === 0} | ||||||
|                   {$_("please-provide-the-required-csv-xlsx-file")} | 							<div class="mb-6"> | ||||||
|                 </p> | 								<p class="text-sm text-gray-500"> | ||||||
|               </div> | 									{$_("please-provide-the-required-csv-xlsx-file")} | ||||||
|               <div class="overflow-hidden relative mt-4 mb-4"> | 								</p> | ||||||
|                 <input | 							</div> | ||||||
|                   accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | 							<div class="overflow-hidden relative mt-4 mb-4"> | ||||||
|                   bind:files | 								<input | ||||||
|                   type="file" | 									accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | ||||||
|                 /> | 									bind:files | ||||||
|               </div> | 									type="file" | ||||||
|               <div class="overflow-hidden relative mt-4 mb-4"> | 								/> | ||||||
|                 <button | 							</div> | ||||||
|                   on:click={() => { | 							<div class="overflow-hidden relative mt-4 mb-4"> | ||||||
|                     cancelModal(); | 								<button | ||||||
|                   }} | 									on:click={() => { | ||||||
|                   type="button" | 										cancelModal(); | ||||||
|                   class="w-full rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 md:ml-40 mr-0 sm:ml-0 sm:w-auto sm:text-sm" | 									}} | ||||||
|                 > | 									type="button" | ||||||
|                   {$_("cancel")} | 									class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|                 </button> | 								> | ||||||
|               </div> | 									{$_("cancel")} | ||||||
|             {/if} | 								</button> | ||||||
|             {#if json_output.length > 0} | 							</div> | ||||||
|               {#if opened_from === "OrgOverview"} | 						{/if} | ||||||
|                 <p>{$_("import__target-organization")}</p> | 						{#if json_output.length > 0} | ||||||
|                 <select | 							{#if opened_from === "OrgOverview"} | ||||||
|                   name="team" | 								<p>{$_("import__target-organization")}</p> | ||||||
|                   bind:value={selected_org} | 								<select | ||||||
|                   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" | 									name="team" | ||||||
|                 > | 									bind:value={selected_org} | ||||||
|                   {#each passed_orgs as o} | 									class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     <option value={o.id}>{o.name}</option> | 								> | ||||||
|                   {/each} | 									{#each passed_orgs as o} | ||||||
|                 </select> | 										<option value={o.id}>{o.name}</option> | ||||||
|                 <p>{$_("confirm-runner-import")}</p> | 									{/each} | ||||||
|               {/if} | 								</select> | ||||||
|               {#if opened_from === "RunnerOverview"} | 								<p>{$_("confirm-runner-import")}</p> | ||||||
|                 <p>{$_("group")}</p> | 							{/if} | ||||||
|                 <Select | 							{#if opened_from === "RunnerOverview"} | ||||||
|                   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" | 								<p>{$_("group")}</p> | ||||||
|                   itemFilter={(label, filterText, option) => | 								<select | ||||||
|                     label.toLowerCase().includes(filterText.toLowerCase()) || | 									bind:value={selected_org_or_team} | ||||||
|                     option.id.value | 									class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                       .toString() | 								> | ||||||
|                       .startsWith(filterText.toLowerCase())} | 									{#each groups as g} | ||||||
|                   items={groups} | 										<option value={g.value}>{g.label}</option> | ||||||
|                   showChevron={true} | 									{/each} | ||||||
|                   placeholder={$_( | 								</select> | ||||||
|                     "search-for-an-organization-or-team-by-name-or-id" | 							{/if} | ||||||
|                   )} | 							{#if opened_from === "OrgDetail"} | ||||||
|                   noOptionsMessage={$_("no-organization-or-team-found")} | 								<p> | ||||||
|                   on:select={(selectedValue) => { | 									{$_("runnerimport_verify_runners_org", { | ||||||
|                     selected_org_or_team = selectedValue.detail.value; | 										values: { org_name: passed_org.name }, | ||||||
|                   }} | 									})} | ||||||
|                   on:clear={() => (selected_org_or_team = null)} | 								</p> | ||||||
|                 /> | 							{/if} | ||||||
|               {/if} | 							<div class="relative w-full mt-4 mb-4"> | ||||||
|               {#if opened_from === "OrgDetail"} | 								<div class="w-full overflow-x-auto max-h-[50vh]"> | ||||||
|                 <p> | 									<table class="divide-y divide-gray-200 w-full"> | ||||||
|                   {$_("runnerimport_verify_runners_org", { | 										<thead class="bg-gray-50"> | ||||||
|                     values: { org_name: passed_org.name }, | 											<tr class="odd:bg-white even:bg-gray-100"> | ||||||
|                   })} | 												<th | ||||||
|                 </p> | 													scope="col" | ||||||
|               {/if} | 													class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|               <input | 												> | ||||||
|                 type="search" | 													{$_("csv_import__firstname")} | ||||||
|                 bind:value={searchvalue} | 												</th> | ||||||
|                 placeholder={$_("datatable.search")} | 												<th | ||||||
|                 aria-label={$_("datatable.search")} | 													scope="col" | ||||||
|                 class="p-2 w-full" | 													class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|               /> | 												> | ||||||
|               <div class="relative w-full mt-4 mb-4"> | 													{$_("csv_import__middlename")} | ||||||
|                 <div class="w-full overflow-x-auto"> | 												</th> | ||||||
|                   <table class="divide-y divide-gray-200 w-full"> | 												<th | ||||||
|                     <thead class="bg-gray-50"> | 													scope="col" | ||||||
|                       <tr class="odd:bg-white even:bg-gray-100"> | 													class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|                         <th | 												> | ||||||
|                           scope="col" | 													{$_("csv_import__lastname")} | ||||||
|                           class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | 												</th> | ||||||
|                         > | 												{#if (opened_from !== "TeamDetail" && opened_from !== "RunnerOverview") || (opened_from === "RunnerOverview" && selected_org_or_team.includes("ORG_"))} | ||||||
|                           {$_("csv_import__firstname")} | 													<th | ||||||
|                         </th> | 														scope="col" | ||||||
|                         <th | 														class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|                           scope="col" | 													> | ||||||
|                           class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | 														{$_("csv_import__team")} | ||||||
|                         > | 													</th> | ||||||
|                           {$_("csv_import__middlename")} | 												{/if} | ||||||
|                         </th> | 											</tr> | ||||||
|                         <th | 										</thead> | ||||||
|                           scope="col" | 										<tbody class="divide-y divide-gray-200"> | ||||||
|                           class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | 											{#each json_output as runner} | ||||||
|                         > | 												{#if Object.values(runner) | ||||||
|                           {$_("csv_import__lastname")} | 													.toString() | ||||||
|                         </th> | 													.toLowerCase() | ||||||
|                         {#if (opened_from !== "TeamDetail" && opened_from !== "RunnerOverview") || (opened_from === "RunnerOverview" && selected_org_or_team.includes("ORG_"))} | 													.includes(searchvalue)} | ||||||
|                           <th | 													<tr class="odd:bg-white even:bg-gray-100"> | ||||||
|                             scope="col" | 														<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                             class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | 															{runner[`${$_("csv_import__firstname")}`]} | ||||||
|                           > | 														</td> | ||||||
|                             {$_("csv_import__team")} | 														<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                           </th> | 															{runner[`${$_("csv_import__middlename")}`] || ""} | ||||||
|                         {/if} | 														</td> | ||||||
|                       </tr> | 														<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                     </thead> | 															{runner[`${$_("csv_import__lastname")}`]} | ||||||
|                     <tbody class="divide-y divide-gray-200"> | 														</td> | ||||||
|                       {#each json_output as runner} | 														{#if (opened_from !== "TeamDetail" && opened_from !== "RunnerOverview") || (opened_from === "RunnerOverview" && selected_org_or_team.includes("ORG_"))} | ||||||
|                         {#if Object.values(runner) | 															<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|                           .toString() | 																{runner[`${$_("csv_import__team")}`] || | ||||||
|                           .toLowerCase() | 																	runner[`${$_("csv_import__class")}`] || | ||||||
|                           .includes(searchvalue)} | 																	"---"} | ||||||
|                           <tr class="odd:bg-white even:bg-gray-100"> | 															</td> | ||||||
|                             <td class="px-6 py-4 whitespace-nowrap"> | 														{/if} | ||||||
|                               {runner[`${$_("csv_import__firstname")}`]} | 													</tr> | ||||||
|                             </td> | 												{/if} | ||||||
|                             <td class="px-6 py-4 whitespace-nowrap"> | 											{/each} | ||||||
|                               {runner[`${$_("csv_import__middlename")}`] || ""} | 										</tbody> | ||||||
|                             </td> | 									</table> | ||||||
|                             <td class="px-6 py-4 whitespace-nowrap"> | 								</div> | ||||||
|                               {runner[`${$_("csv_import__lastname")}`]} | 								<button | ||||||
|                             </td> | 									disabled={!importButtonEnabled} | ||||||
|                             {#if (opened_from !== "TeamDetail" && opened_from !== "RunnerOverview") || (opened_from === "RunnerOverview" && selected_org_or_team.includes("ORG_"))} | 									class:opacity-50={!importButtonEnabled} | ||||||
|                               <td class="px-6 py-4 whitespace-nowrap"> | 									on:click={importAction} | ||||||
|                                 {runner[`${$_("csv_import__team")}`] || | 									type="button" | ||||||
|                                   runner[`${$_("csv_import__class")}`] || | 									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" | ||||||
|                                   "---"} | 								> | ||||||
|                               </td> | 									{$_("import-runners")} | ||||||
|                             {/if} | 								</button> | ||||||
|                           </tr> | 								<button | ||||||
|                         {/if} | 									on:click={() => { | ||||||
|                       {/each} | 										cancelModal(); | ||||||
|                     </tbody> | 									}} | ||||||
|                   </table> | 									type="button" | ||||||
|                 </div> | 									class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500" | ||||||
|                 <button | 								> | ||||||
|                   disabled={!importButtonEnabled} | 									{$_("cancel")} | ||||||
|                   class:opacity-50={!importButtonEnabled} | 								</button> | ||||||
|                   on:click={importAction} | 							</div> | ||||||
|                   type="button" | 						{/if} | ||||||
|                   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" | 					</div> | ||||||
|                 > | 				</div> | ||||||
|                   {$_("import-runners")} | 			</div> | ||||||
|                 </button> | 		</div> | ||||||
|                 <button | 	</div> | ||||||
|                   on:click={() => { |  | ||||||
|                     cancelModal(); |  | ||||||
|                   }} |  | ||||||
|                   type="button" |  | ||||||
|                   class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm" |  | ||||||
|                 > |  | ||||||
|                   {$_("cancel")} |  | ||||||
|                 </button> |  | ||||||
|               </div> |  | ||||||
|             {/if} |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -1,315 +1,302 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | 	import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | ||||||
|   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | 	import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|   import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte"; | 	import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte"; | ||||||
|   import store from "../../store"; | 	import store from "../../store"; | ||||||
|   import { | 	import { | ||||||
|     RunnerService, | 		RunnerService, | ||||||
|     RunnerTeamService, | 		RunnerTeamService, | ||||||
|     RunnerOrganizationService, | 		RunnerOrganizationService, | ||||||
|   } from "@odit/lfk-client-js"; | 	} from "@odit/lfk-client-js"; | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; | 	import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   import isEmail from "validator/es/lib/isEmail"; | 	import isEmail from "validator/es/lib/isEmail"; | ||||||
|   import Select from "svelte-select"; | 	import Select from "svelte-select"; | ||||||
|   import toast from "svelte-french-toast"; | 	import toast from "svelte-french-toast"; | ||||||
|   let data_loaded = false; | 	let data_loaded = false; | ||||||
|   export let params; | 	export let params; | ||||||
|   const runner_promise = RunnerService.runnerControllerGetOne(params.runnerid); | 	const runner_promise = RunnerService.runnerControllerGetOne(params.runnerid); | ||||||
|   $: delete_triggered = false; | 	$: delete_triggered = false; | ||||||
|   $: original_data_pdf = {}; | 	$: original_data_pdf = {}; | ||||||
|   $: original_data = {}; | 	$: original_data = {}; | ||||||
|   $: editable = {}; | 	$: editable = {}; | ||||||
|   $: group = {}; | 	$: group = {}; | ||||||
|   $: changes_performed = !( | 	$: changes_performed = !( | ||||||
|     JSON.stringify(original_data) == JSON.stringify(editable) | 		JSON.stringify(original_data) == JSON.stringify(editable) | ||||||
|   ); | 	); | ||||||
|   $: isEmailValid = | 	$: isEmailValid = | ||||||
|     (editable.email || "") === "" || | 		(editable.email || "") === "" || | ||||||
|     (editable.email && isEmail(editable.email || "")); | 		(editable.email && isEmail(editable.email || "")); | ||||||
|   $: isFirstnameValid = editable.firstname !== ""; | 	$: isFirstnameValid = editable.firstname !== ""; | ||||||
|   $: isLastnameValid = editable.lastname !== ""; | 	$: isLastnameValid = editable.lastname !== ""; | ||||||
|   $: save_enabled = | 	$: save_enabled = | ||||||
|     changes_performed && | 		changes_performed && | ||||||
|     isFirstnameValid && | 		isFirstnameValid && | ||||||
|     isLastnameValid && | 		isLastnameValid && | ||||||
|     isEmailValid && | 		isEmailValid && | ||||||
|     editable.group != null; | 		editable.group != null; | ||||||
|   $: sponsoring_contracts_show = true; | 	$: sponsoring_contracts_show = true; | ||||||
|   $: cards_show = true; | 	$: cards_show = true; | ||||||
|   $: certificates_show = true; | 	$: certificates_show = true; | ||||||
|   $: generate_runners = [original_data_pdf]; | 	$: generate_runners = [original_data_pdf]; | ||||||
|   runner_promise.then((data) => { | 	runner_promise.then((data) => { | ||||||
|     data_loaded = true; | 		data_loaded = true; | ||||||
|     original_data_pdf = Object.assign(original_data_pdf, data); | 		original_data_pdf = Object.assign(original_data_pdf, data); | ||||||
|     data.group = data.group.id; | 		data.group = data.group.id; | ||||||
|     original_data = Object.assign(original_data, data); | 		original_data = Object.assign(original_data, data); | ||||||
|     editable = Object.assign(editable, original_data); | 		editable = Object.assign(editable, original_data); | ||||||
|  |  | ||||||
|     RunnerOrganizationService.runnerOrganizationControllerGetAll().then( | 		RunnerOrganizationService.runnerOrganizationControllerGetAll().then( | ||||||
|       (val) => { | 			(val) => { | ||||||
|         const orgs = val.map((r) => { | 				const orgs = val.map((r) => { | ||||||
|           return { label: r.name, value: r }; | 					return { label: r.name, value: r }; | ||||||
|         }); | 				}); | ||||||
|         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: r }; | 						return { label: `${r.parentGroup.name} > ${r.name}`, value: r }; | ||||||
|           }); | 					}); | ||||||
|           groups = groups.concat(teams); | 					groups = groups.concat(teams); | ||||||
|           group = groups.find((g) => g.value.id == editable.group); | 					group = groups.find((g) => g.value.id == editable.group); | ||||||
|         }); | 				}); | ||||||
|       } | 			} | ||||||
|     ); | 		); | ||||||
|   }); | 	}); | ||||||
|   let groups = []; | 	let groups = []; | ||||||
|   function submit() { | 	function submit() { | ||||||
|     if (data_loaded === true && save_enabled) { | 		if (data_loaded === true && save_enabled) { | ||||||
|       toast.loading($_("updating-runner")); | 			toast.loading($_("updating-runner")); | ||||||
|       let postdata = {}; | 			let postdata = {}; | ||||||
|       postdata = Object.assign(postdata, editable); | 			postdata = Object.assign(postdata, editable); | ||||||
|       if (postdata.phone === "") { | 			if (postdata.phone === "") { | ||||||
|         postdata.phone = null; | 				postdata.phone = null; | ||||||
|       } | 			} | ||||||
|       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; | ||||||
|           toast.dismiss(); | 					toast.dismiss(); | ||||||
|           toast.success($_("runner-updated")); | 					toast.success($_("runner-updated")); | ||||||
|         }) | 				}) | ||||||
|         .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) => {}); | ||||||
|   } | 	} | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#await runner_promise} | {#await runner_promise} | ||||||
|   {$_("loading-runners")} | 	{$_("loading-runners")} | ||||||
| {:then} | {:then} | ||||||
|   <section class="container p-5 select-none"> | 	<section class="container p-5 select-none"> | ||||||
|     <div class="flex flex-row mb-4"> | 		<div class="flex flex-row mb-4"> | ||||||
|       <div class="w-full"> | 			<div class="w-full"> | ||||||
|         <nav class="w-full flex"> | 				<nav class="w-full flex"> | ||||||
|           <ol class="list-none flex flex-row items-center justify-start"> | 					<ol class="list-none flex flex-row items-center justify-start"> | ||||||
|             <li class="flex items-center"> | 						<li class="flex items-center"> | ||||||
|               <svg | 							<a class="mr-2" href="/runners/" | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 								><svg | ||||||
|                 viewBox="0 0 24 24" | 									xmlns="http://www.w3.org/2000/svg" | ||||||
|                 class="flex-shrink-0 w-5 h-5 mr-2" | 									width="24" | ||||||
|                 fill="currentColor" | 									height="24" | ||||||
|                 width="24" | 									viewBox="0 0 24 24" | ||||||
|                 height="24" | 									fill="none" | ||||||
|                 ><path fill="none" d="M0 0h24v24H0z" /> | 									stroke="currentColor" | ||||||
|                 <path | 									stroke-width="2" | ||||||
|                   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" | 									stroke-linecap="round" | ||||||
|                 /></svg | 									stroke-linejoin="round" | ||||||
|               > | 									class="inline-block" | ||||||
|             </li> | 									><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg | ||||||
|             <li class="flex items-center"> | 								> | ||||||
|               <a class="mr-2" href="./">{$_("runners")}</a><svg | 								{$_("runners")}</a | ||||||
|                 stroke="currentColor" | 							> | ||||||
|                 fill="none" | 						</li> | ||||||
|                 stroke-width="2" | 					</ol> | ||||||
|                 viewBox="0 0 24 24" | 				</nav> | ||||||
|                 stroke-linecap="round" | 			</div> | ||||||
|                 stroke-linejoin="round" | 		</div> | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" | 		<div class="mb-4 text-3xl font-extrabold leading-tight"> | ||||||
|                 height="1em" | 			{original_data.firstname} | ||||||
|                 width="1em" | 			{original_data.middlename || ""} | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 			{original_data.lastname} [#{params.runnerid}] | ||||||
|                 ><line x1="5" y1="12" x2="19" y2="12" /> | 			<span data-id="runner_actions_${editable.id}"> | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg | 				{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:DELETE")} | ||||||
|               > | 					<div> | ||||||
|             </li> | 						{#if delete_triggered} | ||||||
|             <li class="flex items-center"> | 							<button | ||||||
|               <span class="mr-2" | 								on:click={deleteRunner} | ||||||
|                 >{original_data.firstname} | 								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:w-auto sm:text-sm" | ||||||
|                 {original_data.middlename || ""} | 								>{$_("confirm-deletion")}</button | ||||||
|                 {original_data.lastname}</span | 							> | ||||||
|               > | 							<button | ||||||
|             </li> | 								on:click={() => { | ||||||
|           </ol> | 									delete_triggered = !delete_triggered; | ||||||
|         </nav> | 								}} | ||||||
|       </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" | ||||||
|     </div> | 								>{$_("cancel")}</button | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> | 							> | ||||||
|       {original_data.firstname} | 						{:else} | ||||||
|       {original_data.middlename || ""} | 							<button | ||||||
|       {original_data.lastname} | 								on:click={() => { | ||||||
|       <span data-id="runner_actions_${editable.id}"> | 									delete_triggered = true; | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:DELETE")} | 								}} | ||||||
|           {#if delete_triggered} | 								type="button" | ||||||
|             <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:w-auto sm:text-sm" | ||||||
|               on:click={deleteRunner} | 								>{$_("delete-runner")}</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" | 							> | ||||||
|               >{$_("confirm-deletion")}</button | 							<button | ||||||
|             > | 								disabled={!save_enabled} | ||||||
|             <button | 								class:opacity-50={!save_enabled} | ||||||
|               on:click={() => { | 								type="button" | ||||||
|                 delete_triggered = !delete_triggered; | 								on:click={submit} | ||||||
|               }} | 								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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|               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" | 								>{$_("save-changes")}</button | ||||||
|               >{$_("cancel")}</button | 							> | ||||||
|             > | 						{/if} | ||||||
|           {/if} | 						<GenerateSponsoringContracts | ||||||
|           <GenerateSponsoringContracts | 							bind:sponsoring_contracts_show | ||||||
|             bind:sponsoring_contracts_show | 							bind:generate_runners | ||||||
|             bind:generate_runners | 						/> | ||||||
|           /> | 						<GenerateRunnerCards bind:cards_show bind:generate_runners /> | ||||||
|           <GenerateRunnerCards bind:cards_show bind:generate_runners /> | 						<GenerateRunnerCertificates | ||||||
|           <GenerateRunnerCertificates | 							bind:certificates_show | ||||||
|             bind:certificates_show | 							bind:generate_runners | ||||||
|             bind:generate_runners | 						/> | ||||||
|           /> | 					</div> | ||||||
|           {#if !delete_triggered} | 				{/if} | ||||||
|             <button | 			</span> | ||||||
|               on:click={() => { | 		</div> | ||||||
|                 delete_triggered = true; | 		<!--  --> | ||||||
|               }} | 		<div class="text-sm w-full mt-2"> | ||||||
|               type="button" | 			<label for="firstname" class="font-semibold text-gray-700" | ||||||
|               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" | 				>{$_("first-name")}</label | ||||||
|               >{$_("delete-runner")}</button | 			> | ||||||
|             > | 			<input | ||||||
|           {/if} | 				autocomplete="off" | ||||||
|         {/if} | 				placeholder={$_("first-name")} | ||||||
|         {#if !delete_triggered} | 				type="text" | ||||||
|           <button | 				class:border-red-500={!isFirstnameValid} | ||||||
|             disabled={!save_enabled} | 				class:focus:border-red-500={!isFirstnameValid} | ||||||
|             class:opacity-50={!save_enabled} | 				class:focus:ring-red-500={!isFirstnameValid} | ||||||
|             type="button" | 				bind:value={editable.firstname} | ||||||
|             on:click={submit} | 				name="firstname" | ||||||
|             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" | 				class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|             >{$_("save-changes")}</button | 			/> | ||||||
|           > | 			{#if !isFirstnameValid} | ||||||
|         {/if} | 				<span | ||||||
|       </span> | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|     </div> | 				> | ||||||
|     <!--  --> | 					{$_("first-name-is-required")} | ||||||
|     <div class="text-sm w-full"> | 				</span> | ||||||
|       <label for="firstname" class="font-medium text-gray-700" | 			{/if} | ||||||
|         >{$_("first-name")}</label | 		</div> | ||||||
|       > | 		<div class="text-sm w-full mt-2"> | ||||||
|       <input | 			<label for="middlename" class="font-semibold text-gray-700" | ||||||
|         autocomplete="off" | 				>{$_("middle-name")}</label | ||||||
|         placeholder={$_("first-name")} | 			> | ||||||
|         type="text" | 			<input | ||||||
|         class:border-red-500={!isFirstnameValid} | 				autocomplete="off" | ||||||
|         class:focus:border-red-500={!isFirstnameValid} | 				placeholder={$_("middle-name")} | ||||||
|         class:focus:ring-red-500={!isFirstnameValid} | 				type="text" | ||||||
|         bind:value={editable.firstname} | 				bind:value={editable.middlename} | ||||||
|         name="firstname" | 				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" | 				class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|       /> | 			/> | ||||||
|       {#if !isFirstnameValid} | 		</div> | ||||||
|         <span | 		<div class="text-sm w-full mt-2"> | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 			<label for="lastname" class="font-semibold text-gray-700" | ||||||
|         > | 				>{$_("last-name")}</label | ||||||
|           {$_("first-name-is-required")} | 			> | ||||||
|         </span> | 			<input | ||||||
|       {/if} | 				autocomplete="off" | ||||||
|     </div> | 				placeholder={$_("last-name")} | ||||||
|     <div class="text-sm w-full"> | 				type="text" | ||||||
|       <label for="middlename" class="font-medium text-gray-700" | 				bind:value={editable.lastname} | ||||||
|         >{$_("middle-name")}</label | 				class:border-red-500={!isLastnameValid} | ||||||
|       > | 				class:focus:border-red-500={!isLastnameValid} | ||||||
|       <input | 				class:focus:ring-red-500={!isLastnameValid} | ||||||
|         autocomplete="off" | 				name="lastname" | ||||||
|         placeholder={$_("middle-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-neutral-800 rounded-md p-2" | ||||||
|         type="text" | 			/> | ||||||
|         bind:value={editable.middlename} | 			{#if !isLastnameValid} | ||||||
|         name="middlename" | 				<span | ||||||
|         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="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|       /> | 				> | ||||||
|     </div> | 					{$_("last-name-is-required")} | ||||||
|     <div class="text-sm w-full"> | 				</span> | ||||||
|       <label for="lastname" class="font-medium text-gray-700" | 			{/if} | ||||||
|         >{$_("last-name")}</label | 		</div> | ||||||
|       > | 		<div class="text-sm w-full mt-2"> | ||||||
|       <input | 			<label for="email" class="font-semibold text-gray-700" | ||||||
|         autocomplete="off" | 				>{$_("e-mail-adress")}</label | ||||||
|         placeholder={$_("last-name")} | 			> | ||||||
|         type="text" | 			<input | ||||||
|         bind:value={editable.lastname} | 				autocomplete="off" | ||||||
|         class:border-red-500={!isLastnameValid} | 				placeholder={$_("e-mail-adress")} | ||||||
|         class:focus:border-red-500={!isLastnameValid} | 				type="email" | ||||||
|         class:focus:ring-red-500={!isLastnameValid} | 				bind:value={editable.email} | ||||||
|         name="lastname" | 				class:border-red-500={!isEmailValid} | ||||||
|         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:focus:border-red-500={!isEmailValid} | ||||||
|       /> | 				class:focus:ring-red-500={!isEmailValid} | ||||||
|       {#if !isLastnameValid} | 				name="email" | ||||||
|         <span | 				class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 			/> | ||||||
|         > | 			{#if !isEmailValid} | ||||||
|           {$_("last-name-is-required")} | 				<span | ||||||
|         </span> | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|       {/if} | 				> | ||||||
|     </div> | 					{$_("valid-email-is-required")} | ||||||
|     <div class="text-sm w-full"> | 				</span> | ||||||
|       <label for="email" class="font-medium text-gray-700" | 			{/if} | ||||||
|         >{$_("e-mail-adress")}</label | 		</div> | ||||||
|       > | 		<div class="text-sm w-full mt-2"> | ||||||
|       <input | 			<label for="phone" class="font-semibold text-gray-700" | ||||||
|         autocomplete="off" | 				>{$_("phone")}</label | ||||||
|         placeholder={$_("e-mail-adress")} | 			> | ||||||
|         type="email" | 			<input | ||||||
|         bind:value={editable.email} | 				autocomplete="off" | ||||||
|         class:border-red-500={!isEmailValid} | 				placeholder={$_("phone")} | ||||||
|         class:focus:border-red-500={!isEmailValid} | 				type="tel" | ||||||
|         class:focus:ring-red-500={!isEmailValid} | 				bind:value={editable.phone} | ||||||
|         name="email" | 				name="phone" | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 				class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|       /> | 			/> | ||||||
|       {#if !isEmailValid} | 		</div> | ||||||
|         <span | 		<div class="text-sm w-full mt-2"> | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | 			<span class="font-semibold text-gray-700">{$_("group")}</span> | ||||||
|         > | 			<Select | ||||||
|           {$_("valid-email-is-required")} | 				containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|         </span> | 				itemFilter={(label, filterText, option) => | ||||||
|       {/if} | 					label.toLowerCase().includes(filterText.toLowerCase()) || | ||||||
|     </div> | 					option.id.value.toString().startsWith(filterText.toLowerCase())} | ||||||
|     <div class="text-sm w-full"> | 				items={groups} | ||||||
|       <label for="phone" class="font-medium text-gray-700">{$_("phone")}</label> | 				showChevron={true} | ||||||
|       <input | 				placeholder={$_("search-for-an-organization-or-team-by-name-or-id")} | ||||||
|         autocomplete="off" | 				noOptionsMessage={$_("no-organization-or-team-found")} | ||||||
|         placeholder={$_("phone")} | 				bind:selectedValue={group} | ||||||
|         type="tel" | 				on:select={(selectedValue) => { | ||||||
|         bind:value={editable.phone} | 					editable.group = selectedValue.detail.value.id; | ||||||
|         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" | 				on:clear={() => (editable.group = null)} | ||||||
|       /> | 			/> | ||||||
|     </div> | 		</div> | ||||||
|     <div class="text-sm w-full"> | 		<div class="text-sm w-full mt-2"> | ||||||
|       <span class="font-medium text-gray-700">{$_("group")}</span> | 			<span class="font-semibold text-gray-700">{$_("distance")}</span> | ||||||
|       <Select | 			<br /> | ||||||
|         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" | 			<span class="text-gray-700">{original_data.distance / 1000} km</span> | ||||||
|         itemFilter={(label, filterText, option) => | 		</div> | ||||||
|           label.toLowerCase().includes(filterText.toLowerCase()) || | 		<div class="text-sm w-full mt-2"> | ||||||
|           option.id.value.toString().startsWith(filterText.toLowerCase())} | 			<span class="font-semibold text-gray-700">{$_('created_via')}</span> | ||||||
|         items={groups} | 			<br /> | ||||||
|         showChevron={true} | 			<span class="text-gray-700">{original_data.created_via}</span> | ||||||
|         placeholder={$_("search-for-an-organization-or-team-by-name-or-id")} | 		</div> | ||||||
|         noOptionsMessage={$_("no-organization-or-team-found")} | 	</section> | ||||||
|         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 / 1000} km</span> |  | ||||||
|     </div> |  | ||||||
|   </section> |  | ||||||
| {:catch error} | {:catch error} | ||||||
|   <PromiseError {error} /> | 	<PromiseError {error} /> | ||||||
| {/await} | {/await} | ||||||
|   | |||||||
| @@ -1,60 +1,337 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { | ||||||
|   import store from "../../store"; | 		RunnerOrganizationService, | ||||||
|   import AddRunnerModal from "./AddRunnerModal.svelte"; | 		RunnerService, | ||||||
|   import ImportRunnerModal from "./ImportRunnerModal.svelte"; | 		RunnerTeamService, | ||||||
|   import RunnersOverview from "./RunnersOverview.svelte"; | 	} from "@odit/lfk-client-js"; | ||||||
|   $: current_runners = []; | 	import { | ||||||
|   export let modal_open = false; | 		createSvelteTable, | ||||||
|   export let import_modal_open = false; | 		flexRender, | ||||||
|   let addRunners; | 		getCoreRowModel, | ||||||
|  | 		getFilteredRowModel, | ||||||
|  | 		getPaginationRowModel, | ||||||
|  | 		getSortedRowModel, | ||||||
|  | 		renderComponent, | ||||||
|  | 	} from "@tanstack/svelte-table"; | ||||||
|  | 	import { onMount } from "svelte"; | ||||||
|  | 	import { writable } from "svelte/store"; | ||||||
|  | 	import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; | ||||||
|  | 	import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte"; | ||||||
|  | 	import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; | ||||||
|  | 	import InputElement from "../shared/InputElement.svelte"; | ||||||
|  | 	import TableActions from "../shared/TableActions.svelte"; | ||||||
|  | 	import { groupFilter } from "../shared/tablefilters"; | ||||||
|  | 	import DeleteRunnerModal from "./DeleteRunnerModal.svelte"; | ||||||
|  | 	import TableBottom from "../shared/TableBottom.svelte"; | ||||||
|  | 	import TableHeader from "../shared/TableHeader.svelte"; | ||||||
|  |  | ||||||
|  | 	$: selectedRunners = | ||||||
|  | 		$table?.getSelectedRowModel().rows.map((row) => row.original) || []; | ||||||
|  | 	$: selected = | ||||||
|  | 		$table?.getSelectedRowModel().rows.map((row) => row.index) || []; | ||||||
|  |  | ||||||
|  | 	$: active_delete = undefined; | ||||||
|  | 	let dataLoaded = false; | ||||||
|  | 	export let created_via = "all"; | ||||||
|  | 	export let current_runners = []; | ||||||
|  | 	$: sponsoring_contracts_show = selected.length > 0; | ||||||
|  | 	$: cards_show = selected.length > 0; | ||||||
|  | 	$: certificates_show = selected.length > 0; | ||||||
|  | 	$: teams = []; | ||||||
|  | 	$: orgs = []; | ||||||
|  |  | ||||||
|  | 	export const addRunners = (runners) => { | ||||||
|  | 		current_runners = current_runners.concat(...runners); | ||||||
|  | 		options.update((options) => ({ | ||||||
|  | 			...options, | ||||||
|  | 			data: current_runners, | ||||||
|  | 		})); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	//Section table | ||||||
|  | 	const columns = [ | ||||||
|  | 		{ | ||||||
|  | 			accessorKey: "id", | ||||||
|  | 			header: () => "id", | ||||||
|  | 			filterFn: `equalsString`, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			accessorKey: "firstname", | ||||||
|  | 			header: () => $_("first-name"), | ||||||
|  | 			filterFn: `includesString`, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			accessorKey: "middlename", | ||||||
|  | 			header: () => $_("middle-name"), | ||||||
|  | 			cell: (info) => { | ||||||
|  | 				if (!info || !info.getValue()) { | ||||||
|  | 					return ""; | ||||||
|  | 				} | ||||||
|  | 				return info.getValue(); | ||||||
|  | 			}, | ||||||
|  | 			filterFn: `includesString`, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			accessorKey: "lastname", | ||||||
|  | 			header: () => $_("last-name"), | ||||||
|  | 			filterFn: `includesString`, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			accessorKey: "created_via", | ||||||
|  | 			header: () => "created_via", | ||||||
|  | 			filterFn: `includesString`, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			accessorKey: "group", | ||||||
|  | 			header: () => $_("group"), | ||||||
|  | 			cell: (info) => { | ||||||
|  | 				const group = info.getValue(); | ||||||
|  | 				if (group.responseType === "RUNNERORGANIZATION") { | ||||||
|  | 					return group.name; | ||||||
|  | 				} | ||||||
|  | 				return `${group.parentGroup.name} > ${group.name}`; | ||||||
|  | 			}, | ||||||
|  | 			filterFn: `group`, | ||||||
|  | 			sortingFn: (rowA, rowB, col) => { | ||||||
|  | 				return rowA.original.group.name.localeCompare(rowB.original.group.name); | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			accessorKey: "distance", | ||||||
|  | 			header: () => $_("distance"), | ||||||
|  | 			sortingFn: (rowA, rowB, col) => { | ||||||
|  | 				return rowA.original.distance > rowB.original.distance; | ||||||
|  | 			}, | ||||||
|  | 			cell: (info) => { | ||||||
|  | 				if (info.getValue() < 1000) { | ||||||
|  | 					return `${info.getValue()} m`; | ||||||
|  | 				} | ||||||
|  | 				return `${(info.getValue() / 1000).toFixed(1)} km`; | ||||||
|  | 			}, | ||||||
|  | 			enableColumnFilter: false, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			accessorKey: "actions", | ||||||
|  | 			header: () => $_("action"), | ||||||
|  | 			cell: (info) => { | ||||||
|  | 				return renderComponent(TableActions, { | ||||||
|  | 					detailsLink: `/runners/${info.row.original.id}`, | ||||||
|  | 					deleteAction: () => { | ||||||
|  | 						active_delete = | ||||||
|  | 							current_runners[ | ||||||
|  | 								current_runners.findIndex((r) => r.id == info.row.original.id) | ||||||
|  | 							]; | ||||||
|  | 					}, | ||||||
|  | 					deleteEnabled: | ||||||
|  | 						store.state.jwtinfo.userdetails.permissions.includes( | ||||||
|  | 							"RUNNER:DELETE" | ||||||
|  | 						), | ||||||
|  | 				}); | ||||||
|  | 			}, | ||||||
|  | 			enableColumnFilter: false, | ||||||
|  | 			enableSorting: false, | ||||||
|  | 		}, | ||||||
|  | 	]; | ||||||
|  | 	const options = writable({ | ||||||
|  | 		data: [], | ||||||
|  | 		columns: columns, | ||||||
|  | 		filterFns: { | ||||||
|  | 			group: groupFilter, | ||||||
|  | 		}, | ||||||
|  | 		initialState: { | ||||||
|  | 			pagination: { | ||||||
|  | 				pageSize: 50, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		enableRowSelection: true, | ||||||
|  | 		getCoreRowModel: getCoreRowModel(), | ||||||
|  | 		getFilteredRowModel: getFilteredRowModel(), | ||||||
|  | 		getPaginationRowModel: getPaginationRowModel(), | ||||||
|  | 		getSortedRowModel: getSortedRowModel(), | ||||||
|  | 	}); | ||||||
|  | 	const table = createSvelteTable(options); | ||||||
|  |  | ||||||
|  | 	async function deleteRunner(delete_runner_id) { | ||||||
|  | 		await RunnerService.runnerControllerRemove(delete_runner_id, true); | ||||||
|  | 		current_runners = current_runners.filter((r) => r.id !== delete_runner_id); | ||||||
|  | 		options.update((options) => ({ | ||||||
|  | 			...options, | ||||||
|  | 			data: current_runners, | ||||||
|  | 		})); | ||||||
|  | 		toast.success($_("runner-deleted")); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	onMount(async () => { | ||||||
|  | 		RunnerTeamService.runnerTeamControllerGetAll().then((val) => { | ||||||
|  | 			teams = val; | ||||||
|  | 		}); | ||||||
|  | 		RunnerOrganizationService.runnerOrganizationControllerGetAll().then( | ||||||
|  | 			(val) => { | ||||||
|  | 				orgs = val; | ||||||
|  | 			} | ||||||
|  | 		); | ||||||
|  |  | ||||||
|  | 		let page = 0; | ||||||
|  | 		while (page >= 0) { | ||||||
|  | 			const runners = await RunnerService.runnerControllerGetAll( | ||||||
|  | 				page, | ||||||
|  | 				500, | ||||||
|  | 				created_via | ||||||
|  | 			); | ||||||
|  | 			if (runners.length == 0) { | ||||||
|  | 				page = -2; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			current_runners = current_runners.concat(...runners); | ||||||
|  | 			options.update((options) => ({ | ||||||
|  | 				...options, | ||||||
|  | 				data: current_runners, | ||||||
|  | 			})); | ||||||
|  |  | ||||||
|  | 			dataLoaded = true; | ||||||
|  | 			page++; | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  | 	import { _ } from "svelte-i18n"; | ||||||
|  | 	import store from "../../store"; | ||||||
|  | 	import AddRunnerModal from "./AddRunnerModal.svelte"; | ||||||
|  | 	import ImportRunnerModal from "./ImportRunnerModal.svelte"; | ||||||
|  | 	import toast from "svelte-french-toast"; | ||||||
|  | 	$: current_runners = []; | ||||||
|  | 	export let modal_open = false; | ||||||
|  | 	export let import_modal_open = false; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> | 	<h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_("runners")} | 		{$_("runners")} | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:CREATE")} | 	</h4> | ||||||
|       <button | 	{#if created_via !== "all"} | ||||||
|         on:click={() => { | 		<p>created_via={created_via}</p> | ||||||
|           modal_open = true; | 	{/if} | ||||||
|         }} | 	{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:CREATE")} | ||||||
|         type="button" | 		<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" | 			on:click={() => { | ||||||
|       > | 				modal_open = true; | ||||||
|         {$_("laeufer-hinzufuegen")} | 			}} | ||||||
|       </button> | 			type="button" | ||||||
|       <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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|         on:click={() => { | 		> | ||||||
|           import_modal_open = true; | 			{$_("laeufer-hinzufuegen")} | ||||||
|         }} | 		</button> | ||||||
|         type="button" | 		<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" | 			on:click={() => { | ||||||
|       > | 				import_modal_open = true; | ||||||
|         {$_("import-runners")} | 			}} | ||||||
|       </button> | 			type="button" | ||||||
|     {/if} | 			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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|   </span> | 		> | ||||||
|   <RunnersOverview bind:current_runners bind:addRunners /> | 			{$_("import-runners")} | ||||||
|  | 		</button> | ||||||
|  | 	{/if} | ||||||
|  | 	<DeleteRunnerModal | ||||||
|  | 		delete_runner={active_delete} | ||||||
|  | 		modal_open={active_delete != undefined} | ||||||
|  | 		on:delete={(event) => { | ||||||
|  | 			deleteRunner(event.detail.id); | ||||||
|  | 		}} | ||||||
|  | 	/> | ||||||
|  | 	{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:GET")} | ||||||
|  | 		{#if !dataLoaded} | ||||||
|  | 			<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">{$_("runners-are-being-loaded")}</p> | ||||||
|  | 				<p class="text-sm">{$_("this-might-take-a-moment")}</p> | ||||||
|  | 			</div> | ||||||
|  | 		{:else} | ||||||
|  | 			<GenerateSponsoringContracts | ||||||
|  | 				bind:sponsoring_contracts_show | ||||||
|  | 				bind:generate_runners={selectedRunners} | ||||||
|  | 			/> | ||||||
|  | 			<GenerateRunnerCards | ||||||
|  | 				bind:cards_show | ||||||
|  | 				bind:generate_runners={selectedRunners} | ||||||
|  | 			/> | ||||||
|  | 			<GenerateRunnerCertificates | ||||||
|  | 				bind:certificates_show | ||||||
|  | 				bind:generate_runners={selectedRunners} | ||||||
|  | 			/> | ||||||
|  | 			<div class="overflow-x-auto"> | ||||||
|  | 				<table class="w-full"> | ||||||
|  | 					<thead class="border-b border-gray-400"> | ||||||
|  | 						{#each $table.getHeaderGroups() as headerGroup} | ||||||
|  | 							<tr class="select-none"> | ||||||
|  | 								<th class="inset-y-0 left-0 px-4 py-2 text-left w-px"> | ||||||
|  | 									<InputElement | ||||||
|  | 										type="checkbox" | ||||||
|  | 										checked={$table.getIsAllRowsSelected()} | ||||||
|  | 										indeterminate={$table.getIsSomeRowsSelected()} | ||||||
|  | 										on:change={() => $table.toggleAllRowsSelected()} | ||||||
|  | 									/> | ||||||
|  | 								</th> | ||||||
|  | 								{#each headerGroup.headers as header} | ||||||
|  | 									<TableHeader {header} /> | ||||||
|  | 								{/each} | ||||||
|  | 							</tr> | ||||||
|  | 						{/each} | ||||||
|  | 					</thead> | ||||||
|  | 					<tbody> | ||||||
|  | 						{#each $table.getRowModel().rows as row} | ||||||
|  | 							<tr class="odd:bg-white even:bg-gray-100"> | ||||||
|  | 								<td class="inset-y-0 left-0 px-4 py-2 text-center w-px"> | ||||||
|  | 									<InputElement | ||||||
|  | 										type="checkbox" | ||||||
|  | 										checked={row.getIsSelected()} | ||||||
|  | 										on:change={() => row.toggleSelected()} | ||||||
|  | 									/> | ||||||
|  | 								</td> | ||||||
|  | 								{#each row.getVisibleCells() as cell} | ||||||
|  | 									<td> | ||||||
|  | 										<svelte:component | ||||||
|  | 											this={flexRender( | ||||||
|  | 												cell.column.columnDef.cell, | ||||||
|  | 												cell.getContext() | ||||||
|  | 											)} | ||||||
|  | 										/> | ||||||
|  | 									</td> | ||||||
|  | 								{/each} | ||||||
|  | 							</tr> | ||||||
|  | 						{/each} | ||||||
|  | 					</tbody> | ||||||
|  | 				</table> | ||||||
|  | 			</div> | ||||||
|  | 			<div class="h-2" /> | ||||||
|  | 		{/if} | ||||||
|  | 	{/if} | ||||||
|  | 	<TableBottom {table} {selected} /> | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:CREATE")} | {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:CREATE")} | ||||||
|   <AddRunnerModal | 	<AddRunnerModal | ||||||
|     bind:modal_open | 		bind:modal_open | ||||||
|     on:created={(event) => { | 		on:created={(event) => { | ||||||
|       addRunners(event.detail.runners); | 			addRunners(event.detail.runners); | ||||||
|     }} | 		}} | ||||||
|   /> | 	/> | ||||||
|   <ImportRunnerModal | 	<ImportRunnerModal | ||||||
|     on:cancelDelete={(event) => { | 		on:cancelDelete={(event) => { | ||||||
|       import_modal_open = false; | 			import_modal_open = false; | ||||||
|     }} | 		}} | ||||||
|     passed_team={{}} | 		passed_team={{}} | ||||||
|     passed_orgs={[]} | 		passed_orgs={[]} | ||||||
|     passed_org={{}} | 		passed_org={{}} | ||||||
|     opened_from="RunnerOverview" | 		opened_from="RunnerOverview" | ||||||
|     bind:import_modal_open | 		bind:import_modal_open | ||||||
|     on:created={(event) => { | 		on:created={(event) => { | ||||||
|       addRunners(event.detail.runners); | 			addRunners(event.detail.runners); | ||||||
|     }} | 		}} | ||||||
|   /> | 	/> | ||||||
| {/if} | {/if} | ||||||
|  |  | ||||||
|  | <style> | ||||||
|  | 	table tbody tr td:nth-child(2) { | ||||||
|  | 		font-family: monospace; | ||||||
|  | 	} | ||||||
|  | </style> | ||||||
|   | |||||||
| @@ -1,267 +0,0 @@ | |||||||
| <script> |  | ||||||
|   import { |  | ||||||
|     RunnerOrganizationService, |  | ||||||
|     RunnerService, |  | ||||||
|     RunnerTeamService, |  | ||||||
|   } from "@odit/lfk-client-js"; |  | ||||||
|   import { |  | ||||||
|     createSvelteTable, |  | ||||||
|     flexRender, |  | ||||||
|     getCoreRowModel, |  | ||||||
|     getFilteredRowModel, |  | ||||||
|     getPaginationRowModel, |  | ||||||
|     getSortedRowModel, |  | ||||||
|     renderComponent, |  | ||||||
|   } from "@tanstack/svelte-table"; |  | ||||||
|   import { onMount } from "svelte"; |  | ||||||
|   import { _ } from "svelte-i18n"; |  | ||||||
|   import { writable } from "svelte/store"; |  | ||||||
|   import store from "../../store"; |  | ||||||
|   import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; |  | ||||||
|   import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte"; |  | ||||||
|   import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; |  | ||||||
|   import InputElement from "../shared/InputElement.svelte"; |  | ||||||
|   import TableActions from "../shared/TableActions.svelte"; |  | ||||||
|   import { groupFilter } from "../shared/tablefilters"; |  | ||||||
|   import DeleteRunnerModal from "./DeleteRunnerModal.svelte"; |  | ||||||
|   import TableBottom from "../shared/TableBottom.svelte"; |  | ||||||
|   import TableHeader from "../shared/TableHeader.svelte"; |  | ||||||
|  |  | ||||||
|   $: selectedRunners = |  | ||||||
|     $table?.getSelectedRowModel().rows.map((row) => row.original) || []; |  | ||||||
|   $: selected = |  | ||||||
|     $table?.getSelectedRowModel().rows.map((row) => row.index) || []; |  | ||||||
|  |  | ||||||
|   $: active_delete = undefined; |  | ||||||
|   let dataLoaded = false; |  | ||||||
|   export let current_runners = []; |  | ||||||
|   $: sponsoring_contracts_show = selected.length > 0; |  | ||||||
|   $: cards_show = selected.length > 0; |  | ||||||
|   $: certificates_show = selected.length > 0; |  | ||||||
|   $: teams = []; |  | ||||||
|   $: orgs = []; |  | ||||||
|  |  | ||||||
|   export const addRunners = (runners) => { |  | ||||||
|     current_runners = current_runners.concat(...runners); |  | ||||||
|     options.update((options) => ({ |  | ||||||
|       ...options, |  | ||||||
|       data: current_runners, |  | ||||||
|     })); |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   //Section table |  | ||||||
|   const columns = [ |  | ||||||
|     { |  | ||||||
|       accessorKey: "id", |  | ||||||
|       header: () => "id", |  | ||||||
|       filterFn: `equalsString`, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       accessorKey: "firstname", |  | ||||||
|       header: () => $_("first-name"), |  | ||||||
|       filterFn: `includesString`, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       accessorKey: "middlename", |  | ||||||
|       header: () => $_("middle-name"), |  | ||||||
|       cell: (info) => { |  | ||||||
|         if (!info || !info.getValue()) { |  | ||||||
|           return ""; |  | ||||||
|         } |  | ||||||
|         return info.getValue(); |  | ||||||
|       }, |  | ||||||
|       filterFn: `includesString`, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       accessorKey: "lastname", |  | ||||||
|       header: () => $_("last-name"), |  | ||||||
|       filterFn: `includesString`, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       accessorKey: "group", |  | ||||||
|       header: () => $_("group"), |  | ||||||
|       cell: (info) => { |  | ||||||
|         const group = info.getValue(); |  | ||||||
|         if (group.responseType === "RUNNERORGANIZATION") { |  | ||||||
|           return group.name; |  | ||||||
|         } |  | ||||||
|         return `${group.parentGroup.name} > ${group.name}`; |  | ||||||
|       }, |  | ||||||
|       filterFn: `group`, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       accessorKey: "distance", |  | ||||||
|       header: () => $_("distance"), |  | ||||||
|       cell: (info) => { |  | ||||||
|         if (info.getValue() < 1000) { |  | ||||||
|           return `${info.getValue()} m`; |  | ||||||
|         } |  | ||||||
|         return `${(info.getValue() / 1000).toFixed(1)} km`; |  | ||||||
|       }, |  | ||||||
|       enableColumnFilter: false, |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       accessorKey: "actions", |  | ||||||
|       header: () => $_("action"), |  | ||||||
|       cell: (info) => { |  | ||||||
|         return renderComponent(TableActions, { |  | ||||||
|           detailsLink: `./${info.row.original.id}`, |  | ||||||
|           deleteAction: () => { |  | ||||||
|             active_delete = |  | ||||||
|               current_runners[ |  | ||||||
|                 current_runners.findIndex((r) => r.id == info.row.original.id) |  | ||||||
|               ]; |  | ||||||
|           }, |  | ||||||
|           deleteEnabled: |  | ||||||
|             store.state.jwtinfo.userdetails.permissions.includes( |  | ||||||
|               "RUNNER:DELETE" |  | ||||||
|             ), |  | ||||||
|         }); |  | ||||||
|       }, |  | ||||||
|       enableColumnFilter: false, |  | ||||||
|       enableSorting: false, |  | ||||||
|     }, |  | ||||||
|   ]; |  | ||||||
|   const options = writable({ |  | ||||||
|     data: [], |  | ||||||
|     columns: columns, |  | ||||||
|     filterFns: { |  | ||||||
|       group: groupFilter, |  | ||||||
|     }, |  | ||||||
|     initialState: { |  | ||||||
|       pagination: { |  | ||||||
|         pageSize: 50, |  | ||||||
|       }, |  | ||||||
|     }, |  | ||||||
|     enableRowSelection: true, |  | ||||||
|     getCoreRowModel: getCoreRowModel(), |  | ||||||
|     getFilteredRowModel: getFilteredRowModel(), |  | ||||||
|     getPaginationRowModel: getPaginationRowModel(), |  | ||||||
|     getSortedRowModel: getSortedRowModel(), |  | ||||||
|   }); |  | ||||||
|   const table = createSvelteTable(options); |  | ||||||
|  |  | ||||||
|   async function deleteRunner(delete_runner_id) { |  | ||||||
|     await RunnerService.runnerControllerRemove(delete_runner_id, true); |  | ||||||
|     current_runners = current_runners.filter((r) => r.id !== delete_runner_id); |  | ||||||
|     options.update((options) => ({ |  | ||||||
|       ...options, |  | ||||||
|       data: current_runners, |  | ||||||
|     })); |  | ||||||
|     toast($_("runner-deleted")); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   onMount(async () => { |  | ||||||
|     RunnerTeamService.runnerTeamControllerGetAll().then((val) => { |  | ||||||
|       teams = val; |  | ||||||
|     }); |  | ||||||
|     RunnerOrganizationService.runnerOrganizationControllerGetAll().then( |  | ||||||
|       (val) => { |  | ||||||
|         orgs = val; |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     let page = 0; |  | ||||||
|     while (page >= 0) { |  | ||||||
|       const runners = await RunnerService.runnerControllerGetAll(page, 500); |  | ||||||
|       if (runners.length == 0) { |  | ||||||
|         page = -2; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       current_runners = current_runners.concat(...runners); |  | ||||||
|       options.update((options) => ({ |  | ||||||
|         ...options, |  | ||||||
|         data: current_runners, |  | ||||||
|       })); |  | ||||||
|  |  | ||||||
|       dataLoaded = true; |  | ||||||
|       page++; |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <DeleteRunnerModal |  | ||||||
|   delete_runner={active_delete} |  | ||||||
|   modal_open={active_delete != undefined} |  | ||||||
|   on:delete={(event) => { |  | ||||||
|     deleteRunner(event.detail.id); |  | ||||||
|   }} |  | ||||||
| /> |  | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:GET")} |  | ||||||
|   {#if !dataLoaded} |  | ||||||
|     <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">{$_("runners-are-being-loaded")}</p> |  | ||||||
|       <p class="text-sm">{$_("this-might-take-a-moment")}</p> |  | ||||||
|     </div> |  | ||||||
|   {:else} |  | ||||||
|     <div class="h-12 mt-2"> |  | ||||||
|       <GenerateSponsoringContracts |  | ||||||
|         bind:sponsoring_contracts_show |  | ||||||
|         bind:generate_runners={selectedRunners} |  | ||||||
|       /> |  | ||||||
|       <GenerateRunnerCards |  | ||||||
|         bind:cards_show |  | ||||||
|         bind:generate_runners={selectedRunners} |  | ||||||
|       /> |  | ||||||
|       <GenerateRunnerCertificates |  | ||||||
|         bind:certificates_show |  | ||||||
|         bind:generate_runners={selectedRunners} |  | ||||||
|       /> |  | ||||||
|     </div> |  | ||||||
|     <div class="overflow-x-auto"> |  | ||||||
|       <table class="w-full"> |  | ||||||
|         <thead class="border-b border-gray-400"> |  | ||||||
|           {#each $table.getHeaderGroups() as headerGroup} |  | ||||||
|             <tr class="select-none"> |  | ||||||
|               <th class="inset-y-0 left-0 px-4 py-2 text-left w-px"> |  | ||||||
|                 <InputElement |  | ||||||
|                   type="checkbox" |  | ||||||
|                   checked={$table.getIsAllRowsSelected()} |  | ||||||
|                   indeterminate={$table.getIsSomeRowsSelected()} |  | ||||||
|                   on:change={() => $table.toggleAllRowsSelected()} |  | ||||||
|                 /> |  | ||||||
|               </th> |  | ||||||
|               {#each headerGroup.headers as header} |  | ||||||
|                 <TableHeader {header} /> |  | ||||||
|               {/each} |  | ||||||
|             </tr> |  | ||||||
|           {/each} |  | ||||||
|         </thead> |  | ||||||
|         <tbody> |  | ||||||
|           {#each $table.getRowModel().rows as row} |  | ||||||
|             <tr class="odd:bg-white even:bg-gray-100"> |  | ||||||
|               <td class="inset-y-0 left-0 px-4 py-2 text-center w-px"> |  | ||||||
|                 <InputElement |  | ||||||
|                   type="checkbox" |  | ||||||
|                   checked={row.getIsSelected()} |  | ||||||
|                   on:change={() => row.toggleSelected()} |  | ||||||
|                 /> |  | ||||||
|               </td> |  | ||||||
|               {#each row.getVisibleCells() as cell} |  | ||||||
|                 <td> |  | ||||||
|                   <svelte:component |  | ||||||
|                     this={flexRender( |  | ||||||
|                       cell.column.columnDef.cell, |  | ||||||
|                       cell.getContext() |  | ||||||
|                     )} |  | ||||||
|                   /> |  | ||||||
|                 </td> |  | ||||||
|               {/each} |  | ||||||
|             </tr> |  | ||||||
|           {/each} |  | ||||||
|         </tbody> |  | ||||||
|       </table> |  | ||||||
|     </div> |  | ||||||
|     <div class="h-2" /> |  | ||||||
|   {/if} |  | ||||||
| {/if} |  | ||||||
| <TableBottom {table} {selected} /> |  | ||||||
|  |  | ||||||
| <style> |  | ||||||
|   table tbody tr td:nth-child(2) { |  | ||||||
|     font-family: monospace; |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -68,14 +68,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -88,15 +88,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -112,18 +112,18 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("create-a-new-scan-fixed-only")} |                 {$_("create-a-new-scan-fixed-only")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "please-provide-the-nessecary-information-to-create-a-new-scan" |                     "please-provide-the-nessecary-information-to-create-a-new-scan" | ||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="donor" |                     for="donor" | ||||||
| @@ -131,7 +131,7 @@ | |||||||
|                     >{$_("runner")}</label |                     >{$_("runner")}</label | ||||||
|                   > |                   > | ||||||
|                   <Select |                   <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" |                     containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     itemFilter={(label, filterText, option) => |                     itemFilter={(label, filterText, option) => | ||||||
|                       filterRunners(label, filterText, option)} |                       filterRunners(label, filterText, option)} | ||||||
|                     items={runners} |                     items={runners} | ||||||
| @@ -160,7 +160,7 @@ | |||||||
|                       type="number" |                       type="number" | ||||||
|                       step="1" |                       step="1" | ||||||
|                       name="donation_amount_eur" |                       name="donation_amount_eur" | ||||||
|                       class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 p-2" |                       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-neutral-800 p-2" | ||||||
|                       placeholder="400" |                       placeholder="400" | ||||||
|                     /> |                     /> | ||||||
|                     <span |                     <span | ||||||
| @@ -180,13 +180,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("create")} |             {$_("create")} | ||||||
|           </button> |           </button> | ||||||
| @@ -195,7 +195,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -33,14 +33,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -53,15 +53,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 xmlns="http://www.w3.org/2000/svg" |                 xmlns="http://www.w3.org/2000/svg" | ||||||
| @@ -76,21 +76,21 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("confirm-delete")} |                 {$_("please-confirm-the-deletion-of-scan")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 {$_("please-confirm-the-deletion-of-scan")} #{delete_scan.id} |                 #{delete_scan.id} | ||||||
|               </div> |               </div> | ||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-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" | ||||||
|           > |           > | ||||||
|             {$_("delete")} |             {$_("delete")} | ||||||
|           </button> |           </button> | ||||||
| @@ -99,7 +99,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -1,288 +1,273 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import store from "../../store"; | 	import store from "../../store"; | ||||||
|   import { RunnerService, ScanService } from "@odit/lfk-client-js"; | 	import { RunnerService, ScanService } from "@odit/lfk-client-js"; | ||||||
|  |  | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; | 	import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   import Select from "svelte-select"; | 	import Select from "svelte-select"; | ||||||
|   let data_loaded = false; | 	let data_loaded = false; | ||||||
|   export let params; | 	export let params; | ||||||
|   $: delete_triggered = false; | 	$: delete_triggered = false; | ||||||
|   $: original_data = {}; | 	$: original_data = {}; | ||||||
|   $: editable = {}; | 	$: editable = {}; | ||||||
|   $: current_runners = []; | 	$: current_runners = []; | ||||||
|   $: is_distance_valid = editable.distance > 0; | 	$: is_distance_valid = editable.distance > 0; | ||||||
|   $: is_everything_set = | 	$: is_everything_set = | ||||||
|     editable.runner != null && | 		editable.runner != null && | ||||||
|     ((original_data.responseType === "TRACKSCAN" && editable.track != null) || | 		((original_data.responseType === "TRACKSCAN" && editable.track != null) || | ||||||
|       original_data.responseType !== "TRACKSCAN"); | 			original_data.responseType !== "TRACKSCAN"); | ||||||
|   $: runner = {}; | 	$: runner = {}; | ||||||
|   $: changes_performed = !( | 	$: changes_performed = !( | ||||||
|     JSON.stringify(original_data) === JSON.stringify(editable) | 		JSON.stringify(original_data) === JSON.stringify(editable) | ||||||
|   ); | 	); | ||||||
|   $: save_enabled = changes_performed && is_everything_set && is_distance_valid; | 	$: save_enabled = changes_performed && is_everything_set && is_distance_valid; | ||||||
|  |  | ||||||
|   const promise = ScanService.scanControllerGetOne(params.scanid).then( | 	const promise = ScanService.scanControllerGetOne(params.scanid).then( | ||||||
|     (data) => { | 		(data) => { | ||||||
|       data_loaded = true; | 			data_loaded = true; | ||||||
|       original_data = Object.assign(original_data, data); | 			original_data = Object.assign(original_data, data); | ||||||
|       original_data.runner = original_data.runner.id; | 			original_data.runner = original_data.runner.id; | ||||||
|       editable = Object.assign(editable, original_data); | 			editable = Object.assign(editable, original_data); | ||||||
|       RunnerService.runnerControllerGetAll().then((val) => { | 			RunnerService.runnerControllerGetAll().then((val) => { | ||||||
|         current_runners = val.map((r) => { | 				current_runners = val.map((r) => { | ||||||
|           return { label: getRunnerLabel(r), value: r }; | 					return { label: getRunnerLabel(r), value: r }; | ||||||
|         }); | 				}); | ||||||
|         runner = current_runners.find((r) => r.value.id == editable.runner); | 				runner = current_runners.find((r) => r.value.id == editable.runner); | ||||||
|       }); | 			}); | ||||||
|     } | 		} | ||||||
|   ); | 	); | ||||||
|   const getRunnerLabel = (option) => | 	const getRunnerLabel = (option) => | ||||||
|     option.firstname + " " + (option.middlename || "") + " " + option.lastname; | 		option.firstname + " " + (option.middlename || "") + " " + option.lastname; | ||||||
|   const filterRunners = (label, filterText, option) => | 	const filterRunners = (label, filterText, option) => | ||||||
|     label.toLowerCase().includes(filterText.toLowerCase()) || | 		label.toLowerCase().includes(filterText.toLowerCase()) || | ||||||
|     option.value.id.toString().startsWith(filterText.toLowerCase()); | 		option.value.id.toString().startsWith(filterText.toLowerCase()); | ||||||
|  |  | ||||||
|   function submit() { | 	function submit() { | ||||||
|     if (data_loaded === true && save_enabled) { | 		if (data_loaded === true && save_enabled) { | ||||||
|       toast($_("scan-is-being-updated")); | 			toast($_("scan-is-being-updated")); | ||||||
|       let postdata = {}; | 			let postdata = {}; | ||||||
|       if (original_data.responseType === "TRACKSCAN") { | 			if (original_data.responseType === "TRACKSCAN") { | ||||||
|         postdata = Object.assign(postdata, editable); | 				postdata = Object.assign(postdata, editable); | ||||||
|         postdata.track = postdata.track.id; | 				postdata.track = postdata.track.id; | ||||||
|         ScanService.scanControllerPutTrackScan(original_data.id, postdata) | 				ScanService.scanControllerPutTrackScan(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; | ||||||
|             toast.success($_("updated-scan")); | 						toast.success($_("updated-scan")); | ||||||
|           }) | 					}) | ||||||
|           .catch((err) => {}); | 					.catch((err) => {}); | ||||||
|       } else { | 			} else { | ||||||
|         postdata = Object.assign(postdata, editable); | 				postdata = Object.assign(postdata, editable); | ||||||
|         ScanService.scanControllerPut(original_data.id, postdata) | 				ScanService.scanControllerPut(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; | ||||||
|             toast.success($_("updated-scan")); | 						toast.success($_("updated-scan")); | ||||||
|           }) | 					}) | ||||||
|           .catch((err) => {}); | 					.catch((err) => {}); | ||||||
|       } | 			} | ||||||
|     } else { | 		} else { | ||||||
|     } | 		} | ||||||
|   } | 	} | ||||||
|   function deleteScan() { | 	function deleteScan() { | ||||||
|     ScanService.scanControllerRemove(original_data.id, false) | 		ScanService.scanControllerRemove(original_data.id, false) | ||||||
|       .then((resp) => { | 			.then((resp) => { | ||||||
|         toast($_("deleted-scan")); | 				toast.success($_("deleted-scan")); | ||||||
|         location.replace("./"); | 				location.replace("./"); | ||||||
|       }) | 			}) | ||||||
|       .catch((err) => { | 			.catch((err) => { | ||||||
|         modal_open = true; | 				modal_open = true; | ||||||
|         delete_scan = original_data; | 				delete_scan = original_data; | ||||||
|       }); | 			}); | ||||||
|   } | 	} | ||||||
|   function format_laptime(laptime) { | 	function format_laptime(laptime) { | ||||||
|     if (laptime == 0 || laptime == null) { | 		if (laptime == 0 || laptime == null) { | ||||||
|       return $_("first-scan-of-the-day"); | 			return $_("first-scan-of-the-day"); | ||||||
|     } | 		} | ||||||
|     if (laptime < 60) { | 		if (laptime < 60) { | ||||||
|       return `${laptime}s`; | 			return `${laptime}s`; | ||||||
|     } | 		} | ||||||
|     if (laptime < 3600) { | 		if (laptime < 3600) { | ||||||
|       return `${Math.floor(laptime / 60)}min ${ | 			return `${Math.floor(laptime / 60)}min ${ | ||||||
|         laptime - Math.floor(laptime / 60) * 60 | 				laptime - Math.floor(laptime / 60) * 60 | ||||||
|       }s`; | 			}s`; | ||||||
|     } | 		} | ||||||
|     return `${Math.floor(laptime / 3600)}h ${ | 		return `${Math.floor(laptime / 3600)}h ${ | ||||||
|       laptime - Math.floor(laptime / 3600) * 3600 | 			laptime - Math.floor(laptime / 3600) * 3600 | ||||||
|     }min ${ | 		}min ${ | ||||||
|       laptime - | 			laptime - | ||||||
|       Math.floor(laptime / 3600) * 3600 - | 			Math.floor(laptime / 3600) * 3600 - | ||||||
|       Math.floor(laptime / 60) * 60 | 			Math.floor(laptime / 60) * 60 | ||||||
|     }`; | 		}`; | ||||||
|   } | 	} | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#await promise} | {#await promise} | ||||||
|   Loading scan details | 	Loading scan details | ||||||
| {:then} | {:then} | ||||||
|   <section class="container p-5 select-none"> | 	<section class="container p-5 select-none"> | ||||||
|     <div class="flex flex-row mb-4"> | 		<div class="flex flex-row mb-4"> | ||||||
|       <div class="w-full"> | 			<div class="w-full"> | ||||||
|         <nav class="w-full flex"> | 				<nav class="w-full flex"> | ||||||
|           <ol class="list-none flex flex-row items-center justify-start"> | 					<ol class="list-none flex flex-row items-center justify-start"> | ||||||
|             <li class="flex items-center"> | 						<li class="flex items-center"> | ||||||
|               <svg | 							<a class="mr-2" href="./" | ||||||
|                 fill="currentColor" | 								><svg | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 									xmlns="http://www.w3.org/2000/svg" | ||||||
|                 viewBox="0 0 24 24" | 									width="24" | ||||||
|                 width="24" | 									height="24" | ||||||
|                 height="24" | 									viewBox="0 0 24 24" | ||||||
|                 ><path | 									fill="none" | ||||||
|                   fill="currentColor" | 									stroke="currentColor" | ||||||
|                   d="M2 4h2v16H2V4zm4 0h1v16H6V4zm2 0h2v16H8V4zm3 0h2v16h-2V4zm3 0h2v16h-2V4zm3 0h1v16h-1V4zm2 0h3v16h-3V4z" | 									stroke-width="2" | ||||||
|                 /></svg | 									stroke-linecap="round" | ||||||
|               > | 									stroke-linejoin="round" | ||||||
|             </li> | 									class="inline-block" | ||||||
|             <li class="flex items-center ml-2"> | 									><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg | ||||||
|               <a class="mr-2" href="./">Scans</a><svg | 								> Scans</a | ||||||
|                 stroke="currentColor" | 							> | ||||||
|                 fill="none" | 						</li> | ||||||
|                 stroke-width="2" | 					</ol> | ||||||
|                 viewBox="0 0 24 24" | 				</nav> | ||||||
|                 stroke-linecap="round" | 			</div> | ||||||
|                 stroke-linejoin="round" | 		</div> | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" | 		<div class="mb-4 text-3xl font-extrabold leading-tight"> | ||||||
|                 height="1em" | 			{runner.value?.firstname} | ||||||
|                 width="1em" | 			{runner.value?.middlename || ""} | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 			{runner.value?.lastname} | ||||||
|                 ><line x1="5" y1="12" x2="19" y2="12" /> | 			- Scan #{original_data.id} | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg | 			<div data-id="donation_actions_${original_data.id}"> | ||||||
|               > | 				{#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:DELETE")} | ||||||
|             </li> | 					{#if delete_triggered} | ||||||
|             <li class="flex items-center"> | 						<button | ||||||
|               <span class="mr-2">{original_data.id}</span> | 							on:click={deleteScan} | ||||||
|             </li> | 							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:w-auto sm:text-sm" | ||||||
|           </ol> | 							>{$_("confirm-deletion")}</button | ||||||
|         </nav> | 						> | ||||||
|       </div> | 						<button | ||||||
|     </div> | 							on:click={() => { | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> | 								delete_triggered = !delete_triggered; | ||||||
|       {runner.value?.firstname} | 							}} | ||||||
|       {runner.value?.middlename || ""} | 							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" | ||||||
|       {runner.value?.lastname} | 							>{$_("cancel")}</button | ||||||
|       #{original_data.id} | 						> | ||||||
|       <span data-id="donation_actions_${original_data.id}"> | 					{/if} | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:DELETE")} | 					{#if !delete_triggered} | ||||||
|           {#if delete_triggered} | 						<button | ||||||
|             <button | 							on:click={() => { | ||||||
|               on:click={deleteScan} | 								delete_triggered = true; | ||||||
|               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:" | 							}} | ||||||
|               >{$_("confirm-deletion")}</button | 							type="button" | ||||||
|             > | 							class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm" | ||||||
|             <button | 							>{$_("delete-scan")}</button | ||||||
|               on:click={() => { | 						> | ||||||
|                 delete_triggered = !delete_triggered; | 					{/if} | ||||||
|               }} | 				{/if} | ||||||
|               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:" | 				{#if !delete_triggered} | ||||||
|               >{$_("cancel")}</button | 					<button | ||||||
|             > | 						disabled={!save_enabled} | ||||||
|           {/if} | 						class:opacity-50={!save_enabled} | ||||||
|           {#if !delete_triggered} | 						type="button" | ||||||
|             <button | 						on:click={submit} | ||||||
|               on:click={() => { | 						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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|                 delete_triggered = true; | 						>{$_("save-changes")}</button | ||||||
|               }} | 					> | ||||||
|               type="button" | 				{/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:" | 			</div> | ||||||
|               >{$_("delete-scan")}</button | 		</div> | ||||||
|             > | 		<!--  --> | ||||||
|           {/if} | 		<div class="w-full inline-flex"> | ||||||
|         {/if} | 			<label for="valid" class="block font-medium text-gray-700" | ||||||
|         {#if !delete_triggered} | 				>{$_("status")}: | ||||||
|           <button | 			</label> | ||||||
|             disabled={!save_enabled} | 			  | ||||||
|             class:opacity-50={!save_enabled} | 			<input | ||||||
|             type="button" | 				id="valid" | ||||||
|             on:click={submit} | 				on:change={() => { | ||||||
|             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:" | 					editable.valid = !editable.valid; | ||||||
|             >{$_("save-changes")}</button | 				}} | ||||||
|           > | 				name="valid" | ||||||
|         {/if} | 				type="checkbox" | ||||||
|       </span> | 				checked={editable.valid} | ||||||
|     </div> | 				class="focus:ring-indigo-500 align-bottom h-7 w-5font-medium text-indigo-600 border-gray-300 rounded" | ||||||
|     <!--  --> | 			/> | ||||||
|     <div class="w-full inline-flex"> | 			  | ||||||
|       <label for="valid" class="block font-medium text-gray-700" | 			<p class="font-medium"> | ||||||
|         >{$_("status")}: | 				{#if editable.valid}{$_("valid")}{:else}{$_("invalid")}{/if} | ||||||
|       </label> | 			</p> | ||||||
|         | 		</div> | ||||||
|       <input | 		{#if editable.responseType === "TRACKSCAN"} | ||||||
|         id="valid" | 			<div class="w-full inline-flex"> | ||||||
|         on:change={() => { | 				<label for="valid" class="block font-semibold text-gray-700" | ||||||
|           editable.valid = !editable.valid; | 					>{$_("track")}: | ||||||
|         }} | 				</label> | ||||||
|         name="valid" | 				<a | ||||||
|         type="checkbox" | 					href="../tracks" | ||||||
|         checked={editable.valid} | 					class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current" | ||||||
|         class="focus:ring-indigo-500 align-bottom h-7 w-5font-medium text-indigo-600 border-gray-300 rounded" | 					>{editable.track.name} | ||||||
|       /> | 				</a> | ||||||
|         | 			</div> | ||||||
|       <p class="font-medium"> | 			<div class="w-full inline-flex pb-3"> | ||||||
|         {#if editable.valid}{$_("valid")}{:else}{$_("invalid")}{/if} | 				<label for="valid" class="block font-semibold text-gray-700" | ||||||
|       </p> | 					>{$_("laptime")}: {format_laptime(editable.laptime)} | ||||||
|     </div> | 				</label> | ||||||
|     {#if editable.responseType === "TRACKSCAN"} | 			</div> | ||||||
|       <div class="w-full inline-flex"> | 		{/if} | ||||||
|         <label for="valid" class="block font-semibold text-gray-700" | 		<div class=" w-full"> | ||||||
|           >{$_("track")}: | 			<label for="runner" class="block font-medium text-gray-700" | ||||||
|         </label> | 				>{$_("runner")}</label | ||||||
|         <a | 			> | ||||||
|           href="../tracks" | 			<Select | ||||||
|           class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800" | 				containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|           >{editable.track.name} | 				itemFilter={(label, filterText, option) => | ||||||
|         </a> | 					filterRunners(label, filterText, option)} | ||||||
|       </div> | 				items={current_runners} | ||||||
|       <div class="w-full inline-flex pb-3"> | 				showChevron={true} | ||||||
|         <label for="valid" class="block font-semibold text-gray-700" | 				isDisabled={editable.responseType === "TRACKSCAN"} | ||||||
|           >{$_("laptime")}: {format_laptime(editable.laptime)} | 				placeholder={$_("search-for-runner-by-name-or-id")} | ||||||
|         </label> | 				noOptionsMessage={$_("no-runners-found")} | ||||||
|       </div> | 				bind:selectedValue={runner} | ||||||
|     {/if} | 				on:select={(selectedValue) => { | ||||||
|     <div class=" w-full"> | 					editable.runner = selectedValue.detail.value.id; | ||||||
|       <label for="runner" class="block font-medium text-gray-700" | 				}} | ||||||
|         >{$_("runner")}</label | 				on:clear={() => (editable.runner = null)} | ||||||
|       > | 			/> | ||||||
|       <Select | 		</div> | ||||||
|         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" | 		<div class=" w-full"> | ||||||
|         itemFilter={(label, filterText, option) => | 			<label | ||||||
|           filterRunners(label, filterText, option)} | 				for="scan_distance" | ||||||
|         items={current_runners} | 				class="block text-sm font-medium text-gray-700" | ||||||
|         showChevron={true} | 			> | ||||||
|         isDisabled={editable.responseType === "TRACKSCAN"} | 				{$_("distance")}</label | ||||||
|         placeholder={$_("search-for-runner-by-name-or-id")} | 			> | ||||||
|         noOptionsMessage={$_("no-runners-found")} | 			<div class="mt-1 flex rounded-md shadow-sm"> | ||||||
|         bind:selectedValue={runner} | 				<input | ||||||
|         on:select={(selectedValue) => { | 					autocomplete="off" | ||||||
|           editable.runner = selectedValue.detail.value.id; | 					class:border-red-500={!is_distance_valid} | ||||||
|         }} | 					class:focus:border-red-500={!is_distance_valid} | ||||||
|         on:clear={() => (editable.runner = null)} | 					class:focus:ring-red-500={!is_distance_valid} | ||||||
|       /> | 					bind:value={editable.distance} | ||||||
|     </div> | 					disabled={editable.responseType === "TRACKSCAN"} | ||||||
|     <div class=" w-full"> | 					type="number" | ||||||
|       <label | 					step="1" | ||||||
|         for="scan_distance" | 					name="scan_distance" | ||||||
|         class="block text-sm font-medium text-gray-700" | 					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-neutral-800 p-2" | ||||||
|       > | 					placeholder="400" | ||||||
|         {$_("distance")}</label | 				/> | ||||||
|       > | 				<span | ||||||
|       <div class="mt-1 flex rounded-md shadow-sm"> | 					class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm" | ||||||
|         <input | 					>m</span | ||||||
|           autocomplete="off" | 				> | ||||||
|           class:border-red-500={!is_distance_valid} | 			</div> | ||||||
|           class:focus:border-red-500={!is_distance_valid} | 			{#if !is_distance_valid} | ||||||
|           class:focus:ring-red-500={!is_distance_valid} | 				<span | ||||||
|           bind:value={editable.distance} | 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" | ||||||
|           disabled={editable.responseType === "TRACKSCAN"} | 				> | ||||||
|           type="number" | 					{$_("the-scans-distance-must-be-greater-than-0m")} | ||||||
|           step="1" | 				</span> | ||||||
|           name="scan_distance" | 			{/if} | ||||||
|           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" | 		</div> | ||||||
|           placeholder="400" | 	</section> | ||||||
|         /> |  | ||||||
|         <span |  | ||||||
|           class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm" |  | ||||||
|           >m</span |  | ||||||
|         > |  | ||||||
|       </div> |  | ||||||
|       {#if !is_distance_valid} |  | ||||||
|         <span |  | ||||||
|           class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1" |  | ||||||
|         > |  | ||||||
|           {$_("the-scans-distance-must-be-greater-than-0m")} |  | ||||||
|         </span> |  | ||||||
|       {/if} |  | ||||||
|     </div> |  | ||||||
|   </section> |  | ||||||
| {:catch error} | {:catch error} | ||||||
|   <PromiseError {error} /> | 	<PromiseError {error} /> | ||||||
| {/await} | {/await} | ||||||
|   | |||||||
| @@ -5,12 +5,12 @@ | |||||||
|  |  | ||||||
| {#if valid} | {#if valid} | ||||||
|   <span |   <span | ||||||
|     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800" |     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-100 text-green-800" | ||||||
|     >{$_("valid")}</span |     >{$_("valid")}</span | ||||||
|   > |   > | ||||||
| {:else} | {:else} | ||||||
|   <span |   <span | ||||||
|     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800" |     class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-red-100 text-red-800" | ||||||
|     >{$_("invalid")}</span |     >{$_("invalid")}</span | ||||||
|   > |   > | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -9,20 +9,20 @@ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> |   <h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_("scans")} |     {$_("scans")} | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:CREATE")} |   </h4> | ||||||
|       <button |   {#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:CREATE")} | ||||||
|         on:click={() => { |     <button | ||||||
|           modal_open = true; |       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" |       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:w-auto sm:text-sm" | ||||||
|         {$_("add-scan")} |     > | ||||||
|       </button> |       {$_("add-scan")} | ||||||
|     {/if} |     </button> | ||||||
|   </span> |   {/if} | ||||||
|   <ScansOverview bind:current_scans bind:addScans /> |   <ScansOverview bind:current_scans bind:addScans /> | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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="m-auto" style="height:15rem" src={scans_empty} alt="" /> |     <img class="m-auto mt-2" 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> | ||||||
|   | |||||||
| @@ -174,12 +174,12 @@ | |||||||
|       ...options, |       ...options, | ||||||
|       data: current_scans, |       data: current_scans, | ||||||
|     })); |     })); | ||||||
|     toast($_("scan-deleted")); |     toast.success($_("scan-deleted")); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   onMount(async () => { |   onMount(async () => { | ||||||
|     let page = 0; |     let page = 0; | ||||||
|     let pagesize = 100; |     let pagesize = 500; | ||||||
|     while (page >= 0) { |     while (page >= 0) { | ||||||
|       const scans = await ScanService.scanControllerGetAll(page, pagesize); |       const scans = await ScanService.scanControllerGetAll(page, pagesize); | ||||||
|       if (scans.length == 0) { |       if (scans.length == 0) { | ||||||
| @@ -194,9 +194,6 @@ | |||||||
|  |  | ||||||
|       dataLoaded = true; |       dataLoaded = true; | ||||||
|       page++; |       page++; | ||||||
|       if (pagesize < 1000) { |  | ||||||
|         pagesize += 100; |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
| </script> | </script> | ||||||
| @@ -223,7 +220,7 @@ | |||||||
|     {#if selected.length > 0} |     {#if selected.length > 0} | ||||||
|       <button |       <button | ||||||
|         type="button" |         type="button" | ||||||
|         class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm inline-flex" |         class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:w-auto sm:text-sm inline-flex" | ||||||
|         id="options-menu" |         id="options-menu" | ||||||
|         on:click={async () => { |         on:click={async () => { | ||||||
|           const prom = []; |           const prom = []; | ||||||
|   | |||||||
| @@ -72,14 +72,14 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={() => { |     on:click_outside={() => { | ||||||
|       modal_open = false; |       modal_open = false; | ||||||
|     }} |     }} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -92,15 +92,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -115,25 +115,25 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:mt-0"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("create-a-new-scanstation")} |                 {$_("create-a-new-scanstation")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "please-provide-the-required-information-to-create-a-new-scanstation" |                     "please-provide-the-required-information-to-create-a-new-scanstation" | ||||||
|                   )} |                   )} | ||||||
|                 </p> |                 </p> | ||||||
|               </div> |               </div> | ||||||
|               <div class="grid grid-cols-6 gap-6"> |               <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label |                   <label | ||||||
|                     for="track" |                     for="track" | ||||||
|                     class="block text-sm font-medium text-gray-700">Track</label |                     class="block text-sm font-medium text-gray-700">Track</label | ||||||
|                   > |                   > | ||||||
|                   <Select |                   <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" |                     containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                     itemFilter={(label, filterText, option) => |                     itemFilter={(label, filterText, option) => | ||||||
|                       label.toLowerCase().includes(filterText.toLowerCase()) || |                       label.toLowerCase().includes(filterText.toLowerCase()) || | ||||||
|                       option.value.id |                       option.value.id | ||||||
| @@ -161,11 +161,11 @@ | |||||||
|                     bind:value={description} |                     bind:value={description} | ||||||
|                     type="text" |                     type="text" | ||||||
|                     name="description" |                     name="description" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="col-span-6"> |                 <div class="col-span-6"> | ||||||
|                   <label for="enabled" class="font-medium text-gray-700" |                   <label for="enabled" class="font-semibold text-gray-700" | ||||||
|                     >{$_("enabled_large")}</label |                     >{$_("enabled_large")}</label | ||||||
|                   > |                   > | ||||||
|                   <br /> |                   <br /> | ||||||
| @@ -188,13 +188,13 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             disabled={!createbtnenabled} |             disabled={!createbtnenabled} | ||||||
|             class:opacity-50={!createbtnenabled} |             class:opacity-50={!createbtnenabled} | ||||||
|             on:click={submit} |             on:click={submit} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" | ||||||
|           > |           > | ||||||
|             {$_("create")} |             {$_("create")} | ||||||
|           </button> |           </button> | ||||||
| @@ -203,7 +203,7 @@ | |||||||
|               modal_open = false; |               modal_open = false; | ||||||
|             }} |             }} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel")} |             {$_("cancel")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -15,7 +15,7 @@ | |||||||
|   function deleteStation() { |   function deleteStation() { | ||||||
|     ScanStationService.scanStationControllerRemove(delete_station.id, true) |     ScanStationService.scanStationControllerRemove(delete_station.id, true) | ||||||
|       .then((resp) => { |       .then((resp) => { | ||||||
|         toast($_("station-deleted")); |         toast.success($_("station-deleted")); | ||||||
|         location.replace("./"); |         location.replace("./"); | ||||||
|       }) |       }) | ||||||
|       .catch((err) => {}); |       .catch((err) => {}); | ||||||
| @@ -24,12 +24,12 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={cancelDelete} |     on:click_outside={cancelDelete} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -42,15 +42,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -62,11 +62,11 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("attention")} |                 {$_("attention")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_( |                   {$_( | ||||||
|                     "do-you-want-to-delete-this-donor-with-all-related-donations" |                     "do-you-want-to-delete-this-donor-with-all-related-donations" | ||||||
| @@ -78,18 +78,18 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             on:click={deleteStation} |             on:click={deleteStation} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500" | ||||||
|           > |           > | ||||||
|             {$_("confirm-delete-station-with-all-scans")} |             {$_("confirm-delete-station-with-all-scans")} | ||||||
|           </button> |           </button> | ||||||
|           <button |           <button | ||||||
|             on:click={cancelDelete} |             on:click={cancelDelete} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel-keep-station")} |             {$_("cancel-keep-station")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -1,200 +1,199 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|  | 	import { tick } from "svelte"; | ||||||
|  | 	import bwipjs from "bwip-js"; | ||||||
|  | 	import toast from "svelte-french-toast"; | ||||||
|  |  | ||||||
|   import { tick, createEventDispatcher } from "svelte"; | 	export let copy_modal_open; | ||||||
|   import bwipjs from "bwip-js"; | 	export let new_station; | ||||||
|  | 	let valueCopy = null; | ||||||
|  | 	let areaDom; | ||||||
|  | 	let copied = false; | ||||||
|  | 	$: is_qrcode = false; | ||||||
|  | 	$: barcode = textToBase64Barcode(new_station.key, is_qrcode); | ||||||
|  |  | ||||||
|   export let copy_modal_open; | 	function close() { | ||||||
|   export let new_station; | 		copy_modal_open = false; | ||||||
|   const dispatch = createEventDispatcher(); | 	} | ||||||
|   let valueCopy = null; | 	async function copy() { | ||||||
|   let areaDom; | 		valueCopy = new_station.key; | ||||||
|   let copied = false; | 		await tick(); | ||||||
|   $: is_qrcode = false; | 		areaDom.focus(); | ||||||
|   $: barcode = textToBase64Barcode(new_station.key, is_qrcode); | 		areaDom.select(); | ||||||
|  | 		try { | ||||||
|  | 			const successful = document.execCommand("copy"); | ||||||
|  | 			if (!successful) { | ||||||
|  | 				throw new Error(); | ||||||
|  | 			} | ||||||
|  | 			toast($_("copied-token-to-clipboard")); | ||||||
|  | 			copied = true; | ||||||
|  | 		} catch (err) { | ||||||
|  | 			toast.Error($_("error-whyile-copying-to-clipboard")); | ||||||
|  | 		} | ||||||
|  | 		// we can notify by event or storage about copy status | ||||||
|  | 		valueCopy = null; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|   function close() { | 	function textToBase64Barcode(text, is_qrcode) { | ||||||
|     copy_modal_open = false; | 		const canvas = document.createElement("canvas"); | ||||||
|   } | 		let bcid = "code128"; | ||||||
|   async function copy() { | 		if (is_qrcode) { | ||||||
|     valueCopy = new_station.key; | 			bcid = "qrcode"; | ||||||
|     await tick(); | 		} | ||||||
|     areaDom.focus(); | 		let codeconfig = { | ||||||
|     areaDom.select(); | 			bcid, | ||||||
|     try { | 			text: `${text}`, | ||||||
|       const successful = document.execCommand("copy"); | 			scale: 4, | ||||||
|       if (!successful) { | 			includetext: true, | ||||||
|         throw new Error(); | 			textxalign: "center", | ||||||
|       } | 			backgroundcolor: "ffffff", | ||||||
|       toast($_("copied-token-to-clipboard")); | 		}; | ||||||
|       copied = true; | 		if (bcid == "code128") { | ||||||
|     } catch (err) { | 			codeconfig.height = 10; | ||||||
|       toast.Error($_("error-whyile-copying-to-clipboard")); | 		} | ||||||
|     } | 		bwipjs.toCanvas(canvas, codeconfig); | ||||||
|     // we can notify by event or storage about copy status | 		return canvas.toDataURL("image/png"); | ||||||
|     valueCopy = null; | 	} | ||||||
|   } |  | ||||||
|  |  | ||||||
|   function textToBase64Barcode(text, is_qrcode) { |  | ||||||
|     const canvas = document.createElement("canvas"); |  | ||||||
|     let bcid = "code128"; |  | ||||||
|     if (is_qrcode) { |  | ||||||
|       bcid = "qrcode"; |  | ||||||
|     } |  | ||||||
|     let codeconfig = { |  | ||||||
|       bcid, |  | ||||||
|       text: `${text}`, |  | ||||||
|       scale: 4, |  | ||||||
|       includetext: true, |  | ||||||
|       textxalign: "center", |  | ||||||
|       backgroundcolor: "ffffff", |  | ||||||
|     }; |  | ||||||
|     if (bcid == "code128") { |  | ||||||
|       codeconfig.height = 10; |  | ||||||
|     } |  | ||||||
|     bwipjs.toCanvas(canvas, codeconfig); |  | ||||||
|     return canvas.toDataURL("image/png"); |  | ||||||
|   } |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if copy_modal_open} | {#if copy_modal_open} | ||||||
|   {#if valueCopy != null} | 	{#if valueCopy != null} | ||||||
|     <textarea bind:this={areaDom}>{valueCopy}</textarea> | 		<textarea bind:this={areaDom}>{valueCopy}</textarea> | ||||||
|   {/if} | 	{/if} | ||||||
|   <div class="fixed z-10 inset-0 overflow-y-auto"> | 	<div class="fixed z-10 inset-0 overflow-y-hidden"> | ||||||
|     <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 h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > | 		> | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | 			<div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div | 				<div | ||||||
|           class="absolute inset-0 bg-gray-500 opacity-75" | 					class="absolute inset-0 bg-gray-500 opacity-75" | ||||||
|           data-id="modal_backdrop" | 					data-id="modal_backdrop" | ||||||
|         /> | 				/> | ||||||
|       </div> | 			</div> | ||||||
|       <span | 			<span | ||||||
|         class="hidden sm:inline-block sm:align-middle sm:h-screen" | 				class="hidden sm:inline-block sm:align-middle sm:h-screen" | ||||||
|         aria-hidden="true">​</span | 				aria-hidden="true">​</span | ||||||
|       > | 			> | ||||||
|       <div | 			<div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" | 				class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" | 				role="dialog" | ||||||
|         aria-modal="true" | 				aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" | 				aria-labelledby="modal-headline" | ||||||
|       > | 			> | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> | 				<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> | 					<div class=""> | ||||||
|             <div | 						<div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | 							class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > | 						> | ||||||
|               <svg | 							<svg | ||||||
|                 class="h-6 w-6 text-blue-600" | 								class="h-6 w-6 text-blue-600" | ||||||
|                 fill="currentColor" | 								fill="currentColor" | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 								xmlns="http://www.w3.org/2000/svg" | ||||||
|                 viewBox="0 0 24 24" | 								viewBox="0 0 24 24" | ||||||
|                 ><path fill="none" d="M0 0h24v24H0z" /> | 								><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|                 <path | 								<path | ||||||
|                   d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" | 									d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" | ||||||
|                 /></svg | 								/></svg | ||||||
|               > | 							> | ||||||
|             </div> | 						</div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> | 						<div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> | 							<h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("token")} | 								{$_("token")} | ||||||
|               </h3> | 							</h3> | ||||||
|               <div class="mt-2 mb-6"> | 							<div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> | 								<p class="text-sm text-gray-500"> | ||||||
|                   {$_( | 									{$_( | ||||||
|                     "the-scanstations-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again" | 										"the-scanstations-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again" | ||||||
|                   )} | 									)} | ||||||
|                   <br /> | 									<br /> | ||||||
|                   {$_("please-copy-the-token-and-store-it-somewhere-save")} | 									{$_("please-copy-the-token-and-store-it-somewhere-save")} | ||||||
|                 </p> | 								</p> | ||||||
|               </div> | 							</div> | ||||||
|               <div class="mt-2 mb-6"> | 							<div class="mb-6"> | ||||||
|                 <label | 								<label | ||||||
|                   for="token" | 									for="token" | ||||||
|                   class="block text-sm font-medium text-gray-700" | 									class="block text-sm font-medium text-gray-700" | ||||||
|                   >{$_("token")}</label | 									>{$_("token")}</label | ||||||
|                 > | 								> | ||||||
|                 <button on:click={copy} class="inline-flex"> | 								<button on:click={copy} class="inline-flex"> | ||||||
|                   <p | 									<p | ||||||
|                     name="token" | 										name="token" | ||||||
|                     class:bg-green-200={copied} | 										class:bg-green-200={copied} | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 p-2" | 										class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 p-2" | ||||||
|                   > | 									> | ||||||
|                     {new_station.key} | 										{new_station.key} | ||||||
|                   </p> | 									</p> | ||||||
|                   <div | 									<div | ||||||
|                     class="bg-gray-200 border-gray-300 border-t border-b border-r text-black rounded-r-md sm:text-sm p-2 mt-1 cursor-pointer" | 										class="bg-gray-200 border-gray-300 border-t border-b border-r text-black rounded-r-md sm:text-sm p-2 mt-1 cursor-pointer" | ||||||
|                   > | 									> | ||||||
|                     <svg | 										<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" | ||||||
|                       width="24" | 											width="24" | ||||||
|                       height="24" | 											height="24" | ||||||
|                       ><path fill="none" d="M0 0h24v24H0z" /> | 											><path fill="none" d="M0 0h24v24H0z" /> | ||||||
|                       <path | 											<path | ||||||
|                         fill="currentColor" | 												fill="currentColor" | ||||||
|                         d="M7 4V2h10v2h3l1 1v16a1 1 0 01-1 1H4a1 1 0 01-1-1V5l1-1h3zm0 2H5v14h14V6h-2v2H7V6zm2-2v2h6V4H9z" | 												d="M7 4V2h10v2h3l1 1v16a1 1 0 01-1 1H4a1 1 0 01-1-1V5l1-1h3zm0 2H5v14h14V6h-2v2H7V6zm2-2v2h6V4H9z" | ||||||
|                       /></svg | 											/></svg | ||||||
|                     > | 										> | ||||||
|                   </div> | 									</div> | ||||||
|                 </button> | 								</button> | ||||||
|                 <p class="text-gray-500 text-xs"> | 								<p class="text-gray-500 text-xs"> | ||||||
|                   {$_("click-to-copy-token-to-clipboard")} | 									{$_("click-to-copy-token-to-clipboard")} | ||||||
|                 </p> | 								</p> | ||||||
|               </div> | 							</div> | ||||||
|             </div> | 						</div> | ||||||
|           </div> | 					</div> | ||||||
|           <div class="mx-auto text-center items-center"> | 					<div class="mx-auto text-center items-center"> | ||||||
|             <h2 class="text-lg leading-6 font-medium text-gray-900"> | 						<h2 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|               {$_("config-codes")} | 							{$_("config-codes")} | ||||||
|             </h2> | 						</h2> | ||||||
|             <span class="flex items-center text-center"> | 						<span class="flex items-center text-center"> | ||||||
|               <p class="text-md text-gray-900 mr-3">Format:</p> | 							<p class="text-md text-gray-900 mr-3">Format:</p> | ||||||
|               <label for="codeswitch" class="text-md text-gray-900 mr-3" | 							<label for="codeswitch" class="text-md text-gray-900 mr-3" | ||||||
|                 >Code128</label | 								>Code128</label | ||||||
|               > | 							> | ||||||
|               <input | 							<input | ||||||
|                 id="codeswitch" | 								id="codeswitch" | ||||||
|                 type="checkbox" | 								type="checkbox" | ||||||
|                 bind:checked={is_qrcode} | 								bind:checked={is_qrcode} | ||||||
|                 class="relative shrink-0 w-[3.25rem] h-7 bg-gray-100 checked:bg-none checked:bg-blue-600 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 ring-1 ring-transparent focus:border-blue-600 focus:ring-blue-600 ring-offset-white focus:outline-none appearance-none before:inline-block before:w-6 before:h-6 before:bg-white checked:before:bg-blue-200 before:translate-x-0 checked:before:translate-x-full before:shadow before:rounded-full before:transform before:ring-0 before:transition before:ease-in-out before:duration-200" | 								class="relative shrink-0 w-[3.25rem] h-7 bg-gray-100 checked:bg-none checked:bg-blue-600 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 ring-1 ring-transparent focus:border-blue-600 focus:ring-blue-600 ring-offset-white focus:outline-none appearance-none before:inline-block before:w-6 before:h-6 before:bg-white checked:before:bg-blue-200 before:translate-x-0 checked:before:translate-x-full before:shadow before:rounded-full before:transform before:ring-0 before:transition before:ease-in-out before:duration-200" | ||||||
|               /> | 							/> | ||||||
|               <label for="codeswitch" class="text-md text-gray-900 ml-3" | 							<label for="codeswitch" class="text-md text-gray-900 ml-3" | ||||||
|                 >QR-Code</label | 								>QR-Code</label | ||||||
|               > | 							> | ||||||
|             </span> | 						</span> | ||||||
|             <h3 class="leading-6 font-medium text-gray-900"> | 						<h3 class="leading-6 font-medium text-gray-900"> | ||||||
|               {$_("api-endpoint")} | 							{$_("api-endpoint")} | ||||||
|             </h3> | 						</h3> | ||||||
|             <img | 						<img | ||||||
|               class:w-[50%]={is_qrcode} | 							class:w-[50%]={is_qrcode} | ||||||
|               class:w-full={!is_qrcode} | 							class:w-full={!is_qrcode} | ||||||
|               class="md:w-auto mb-2 mx-auto" | 							class="w-full lg:max-w-[50vw] lg:max-h-[10rem] object-contain mb-2 mx-auto" | ||||||
|               alt="Registrierungscode" | 							alt="Registrierungscode" | ||||||
|               src={textToBase64Barcode(window.config.baseurl, is_qrcode)} | 							src={textToBase64Barcode(window.config.baseurl, is_qrcode)} | ||||||
|             /> | 						/> | ||||||
|             <h3 class="leading-6 font-medium text-gray-900">{$_("token")}</h3> | 						<h3 class="leading-6 font-medium text-gray-900">{$_("token")}</h3> | ||||||
|             <img | 						<img | ||||||
|               class:w-[50%]={is_qrcode} | 							class:w-[50%]={is_qrcode} | ||||||
|               class:w-full={!is_qrcode} | 							class:w-full={!is_qrcode} | ||||||
|               class="md:w-auto mb-2 mx-auto" | 							class="w-full lg:max-w-[50vw] lg:max-h-[10rem] object-contain mb-2 mx-auto" | ||||||
|               alt="Registrierungscode" | 							alt="Registrierungscode" | ||||||
|               src={barcode} | 							src={barcode} | ||||||
|             /> | 						/> | ||||||
|           </div> | 					</div> | ||||||
|         </div> | 				</div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> | 				<div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button | 					<button | ||||||
|             on:click={close} | 						on:click={close} | ||||||
|             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-green-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm" | 						class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-green-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500" | ||||||
|           > | 					> | ||||||
|             {$_("yes-i-copied-the-token")} | 						{$_("yes-i-copied-the-token")} | ||||||
|           </button> | 					</button> | ||||||
|         </div> | 				</div> | ||||||
|       </div> | 			</div> | ||||||
|     </div> | 		</div> | ||||||
|   </div> | 	</div> | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -1,204 +1,190 @@ | |||||||
| <script> | <script> | ||||||
|   import { t, _ } from "svelte-i18n"; | 	import { t, _ } from "svelte-i18n"; | ||||||
|   import store from "../../store"; | 	import store from "../../store"; | ||||||
|   import { ScanStationService, TrackService } from "@odit/lfk-client-js"; | 	import { ScanStationService, TrackService } from "@odit/lfk-client-js"; | ||||||
|  |  | ||||||
|   import PromiseError from "../base/PromiseError.svelte"; | 	import PromiseError from "../base/PromiseError.svelte"; | ||||||
|   import ConfirmScanStationDeletion from "./ConfirmScanStationDeletion.svelte"; | 	import ConfirmScanStationDeletion from "./ConfirmScanStationDeletion.svelte"; | ||||||
|   import Select from "svelte-select"; | 	import Select from "svelte-select"; | ||||||
|   let data_loaded = false; | 	let data_loaded = false; | ||||||
|   let modal_open; | 	let modal_open; | ||||||
|   let delete_station; | 	let delete_station; | ||||||
|   export let params; | 	export let params; | ||||||
|   $: delete_triggered = false; | 	$: delete_triggered = false; | ||||||
|   $: original_data = {}; | 	$: original_data = {}; | ||||||
|   $: editable = {}; | 	$: editable = {}; | ||||||
|   $: tracks = []; | 	$: tracks = []; | ||||||
|   $: track = {}; | 	$: track = {}; | ||||||
|   $: changes_performed = !( | 	$: changes_performed = !( | ||||||
|     JSON.stringify(original_data) === JSON.stringify(editable) | 		JSON.stringify(original_data) === JSON.stringify(editable) | ||||||
|   ); | 	); | ||||||
|   $: save_enabled = changes_performed; | 	$: save_enabled = changes_performed; | ||||||
|   const promise = ScanStationService.scanStationControllerGetOne( | 	const promise = ScanStationService.scanStationControllerGetOne( | ||||||
|     params.stationid | 		params.stationid | ||||||
|   ).then((data) => { | 	).then((data) => { | ||||||
|     data_loaded = true; | 		data_loaded = true; | ||||||
|     data.track = data.track.id; | 		data.track = data.track.id; | ||||||
|     original_data = Object.assign(original_data, data); | 		original_data = Object.assign(original_data, data); | ||||||
|     editable = Object.assign(editable, original_data); | 		editable = Object.assign(editable, original_data); | ||||||
|     TrackService.trackControllerGetAll().then((val) => { | 		TrackService.trackControllerGetAll().then((val) => { | ||||||
|       tracks = val.map((t) => { | 			tracks = val.map((t) => { | ||||||
|         return { label: t.name || `#{t.id}`, value: t }; | 				return { label: t.name || `#{t.id}`, value: t }; | ||||||
|       }); | 			}); | ||||||
|       track = tracks.find((t) => t.value.id == editable.track); | 			track = tracks.find((t) => t.value.id == editable.track); | ||||||
|     }); | 		}); | ||||||
|   }); | 	}); | ||||||
|   function submit() { | 	function submit() { | ||||||
|     if (data_loaded === true && save_enabled) { | 		if (data_loaded === true && save_enabled) { | ||||||
|       toast($_("station-is-being-updated")); | 			toast($_("station-is-being-updated")); | ||||||
|       ScanStationService.scanStationControllerPut(original_data.id, editable) | 			ScanStationService.scanStationControllerPut(original_data.id, editable) | ||||||
|         .then((resp) => { | 				.then((resp) => { | ||||||
|           Object.assign(original_data, editable); | 					Object.assign(original_data, editable); | ||||||
|           original_data = original_data; | 					original_data = original_data; | ||||||
|           toast.success($_("updated-station")); | 					toast.success($_("updated-station")); | ||||||
|         }) | 				}) | ||||||
|         .catch((err) => {}); | 				.catch((err) => {}); | ||||||
|     } else { | 		} else { | ||||||
|     } | 		} | ||||||
|   } | 	} | ||||||
|   function deleteStation() { | 	function deleteStation() { | ||||||
|     ScanStationService.scanStationControllerRemove(original_data.id, false) | 		ScanStationService.scanStationControllerRemove(original_data.id, false) | ||||||
|       .then((resp) => { | 			.then((resp) => { | ||||||
|         toast($_("station-deleted")); | 				toast.success($_("station-deleted")); | ||||||
|         location.replace("./"); | 				location.replace("./"); | ||||||
|       }) | 			}) | ||||||
|       .catch((err) => { | 			.catch((err) => { | ||||||
|         modal_open = true; | 				modal_open = true; | ||||||
|         delete_station = original_data; | 				delete_station = original_data; | ||||||
|       }); | 			}); | ||||||
|   } | 	} | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <ConfirmScanStationDeletion bind:modal_open bind:delete_station /> | <ConfirmScanStationDeletion bind:modal_open bind:delete_station /> | ||||||
| {#await promise} | {#await promise} | ||||||
|   {$_("loading-station-details")} | 	{$_("loading-station-details")} | ||||||
| {:then} | {:then} | ||||||
|   <section class="container p-5 select-none"> | 	<section class="container p-5 select-none"> | ||||||
|     <div class="flex flex-row mb-4"> | 		<div class="flex flex-row mb-4"> | ||||||
|       <div class="w-full"> | 			<div class="w-full"> | ||||||
|         <nav class="w-full flex"> | 				<nav class="w-full flex"> | ||||||
|           <ol class="list-none flex flex-row items-center justify-start"> | 					<ol class="list-none flex flex-row items-center justify-start"> | ||||||
|             <li class="flex items-center"> | 						<li class="flex items-center"> | ||||||
|               <svg | 							<a class="mr-2" href="./" | ||||||
|                 fill="currentColor" | 								><svg | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 									xmlns="http://www.w3.org/2000/svg" | ||||||
|                 viewBox="0 0 24 24" | 									width="24" | ||||||
|                 width="24" | 									height="24" | ||||||
|                 height="24" | 									viewBox="0 0 24 24" | ||||||
|                 ><path fill="none" d="M0 0h24v24H0z" /> | 									fill="none" | ||||||
|                 <path | 									stroke="currentColor" | ||||||
|                   d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" | 									stroke-width="2" | ||||||
|                 /></svg | 									stroke-linecap="round" | ||||||
|               > | 									stroke-linejoin="round" | ||||||
|             </li> | 									class="inline-block" | ||||||
|             <li class="flex items-center ml-2"> | 									><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg | ||||||
|               <a class="mr-2" href="./">{$_("scanstation")}</a><svg | 								> | ||||||
|                 stroke="currentColor" | 								{$_("scanstations")}</a | ||||||
|                 fill="none" | 							> | ||||||
|                 stroke-width="2" | 						</li> | ||||||
|                 viewBox="0 0 24 24" | 					</ol> | ||||||
|                 stroke-linecap="round" | 				</nav> | ||||||
|                 stroke-linejoin="round" | 			</div> | ||||||
|                 class="h-3 w-3 mr-2 stroke-current" | 		</div> | ||||||
|                 height="1em" | 		<div class="mb-4 text-3xl font-extrabold leading-tight"> | ||||||
|                 width="1em" | 			{$_("scanstation")} #{original_data.id}<br>"{original_data.description}" | ||||||
|                 xmlns="http://www.w3.org/2000/svg" | 			<div data-id="stations_actions_${editable.id}"> | ||||||
|                 ><line x1="5" y1="12" x2="19" y2="12" /> | 				{#if store.state.jwtinfo.userdetails.permissions.includes("STATION:DELETE")} | ||||||
|                 <polyline points="12 5 19 12 12 19" /></svg | 					{#if delete_triggered} | ||||||
|               > | 						<button | ||||||
|             </li> | 							on:click={deleteStation} | ||||||
|             <li class="flex items-center"> | 							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:w-auto sm:text-sm" | ||||||
|               <span class="mr-2">#{original_data.id}</span> | 							>{$_("confirm-deletion")}</button | ||||||
|             </li> | 						> | ||||||
|           </ol> | 						<button | ||||||
|         </nav> | 							on:click={() => { | ||||||
|       </div> | 								delete_triggered = !delete_triggered; | ||||||
|     </div> | 							}} | ||||||
|     <div class="mb-8 text-3xl font-extrabold leading-tight"> | 							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" | ||||||
|       #{original_data.id} | 							>{$_("cancel")}</button | ||||||
|       <span data-id="stations_actions_${editable.id}"> | 						> | ||||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("STATION:DELETE")} | 					{/if} | ||||||
|           {#if delete_triggered} | 					{#if !delete_triggered} | ||||||
|             <button | 						<button | ||||||
|               on:click={deleteStation} | 							on:click={() => { | ||||||
|               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_triggered = true; | ||||||
|               >{$_("confirm-deletion")}</button | 							}} | ||||||
|             > | 							type="button" | ||||||
|             <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:w-auto sm:text-sm" | ||||||
|               on:click={() => { | 							>{$_("delete-station")}</button | ||||||
|                 delete_triggered = !delete_triggered; | 						> | ||||||
|               }} | 					{/if} | ||||||
|               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" | 				{/if} | ||||||
|               >{$_("cancel")}</button | 				{#if !delete_triggered} | ||||||
|             > | 					<button | ||||||
|           {/if} | 						disabled={!save_enabled} | ||||||
|           {#if !delete_triggered} | 						class:opacity-50={!save_enabled} | ||||||
|             <button | 						type="button" | ||||||
|               on:click={() => { | 						on:click={submit} | ||||||
|                 delete_triggered = true; | 						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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|               }} | 						>{$_("save-changes")}</button | ||||||
|               type="button" | 					> | ||||||
|               class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm" | 				{/if} | ||||||
|               >{$_("delete-station")}</button | 			</div> | ||||||
|             > | 		</div> | ||||||
|           {/if} | 		<!--  --> | ||||||
|         {/if} | 		<div class="mt-2 text-sm w-full"> | ||||||
|         {#if !delete_triggered} | 			<label for="track" class="block text-sm font-semibold text-gray-700" | ||||||
|           <button | 				>Track</label | ||||||
|             disabled={!save_enabled} | 			> | ||||||
|             class:opacity-50={!save_enabled} | 			<Select | ||||||
|             type="button" | 				containerClasses="rounded-l-md focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|             on:click={submit} | 				itemFilter={(label, filterText, option) => | ||||||
|             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" | 					label.toLowerCase().includes(filterText.toLowerCase()) || | ||||||
|             >{$_("save-changes")}</button | 					option.value.id.toString().startsWith(filterText.toLowerCase())} | ||||||
|           > | 				items={tracks} | ||||||
|         {/if} | 				showChevron={true} | ||||||
|       </span> | 				placeholder="Search for a track (by name or id)." | ||||||
|     </div> | 				noOptionsMessage="No track found" | ||||||
|     <!--  --> | 				bind:selectedValue={track} | ||||||
|     <div class="text-sm w-full"> | 				on:select={(selectedValue) => | ||||||
|       <label for="track" class="block text-sm font-medium text-gray-700" | 					(editable.track = selectedValue.detail.value.id)} | ||||||
|         >Track</label | 				on:clear={() => (track = null)} | ||||||
|       > | 			/> | ||||||
|       <Select | 		</div> | ||||||
|         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" | 		<div class="mt-2 text-sm w-full"> | ||||||
|         itemFilter={(label, filterText, option) => | 			<label for="description" class="font-semibold text-gray-700" | ||||||
|           label.toLowerCase().includes(filterText.toLowerCase()) || | 				>{$_("description")}</label | ||||||
|           option.value.id.toString().startsWith(filterText.toLowerCase())} | 			> | ||||||
|         items={tracks} | 			<input | ||||||
|         showChevron={true} | 				autocomplete="off" | ||||||
|         placeholder="Search for a track (by name or id)." | 				placeholder={$_("description")} | ||||||
|         noOptionsMessage="No track found" | 				type="text" | ||||||
|         bind:selectedValue={track} | 				bind:value={editable.description} | ||||||
|         on:select={(selectedValue) => | 				name="description" | ||||||
|           (editable.track = selectedValue.detail.value.id)} | 				class="focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|         on:clear={() => (track = null)} | 			/> | ||||||
|       /> | 		</div> | ||||||
|     </div> | 		<div class="mt-2 text-sm w-full"> | ||||||
|     <div class="text-sm w-full"> | 			<label for="enabled" class="font-semibold text-gray-700" | ||||||
|       <label for="description" class="font-medium text-gray-700" | 				>{$_("enabled")}</label | ||||||
|         >{$_("description")}</label | 			> | ||||||
|       > | 			<br /> | ||||||
|       <input | 			<p class="text-gray-500"> | ||||||
|         autocomplete="off" | 				<input | ||||||
|         placeholder={$_("description")} | 					id="enabled" | ||||||
|         type="text" | 					on:change={() => { | ||||||
|         bind:value={editable.description} | 						editable.enabled = !editable.enabled; | ||||||
|         name="description" | 					}} | ||||||
|         class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" | 					name="enabled" | ||||||
|       /> | 					type="checkbox" | ||||||
|     </div> | 					checked={editable.enabled} | ||||||
|     <div class="text-sm w-full"> | 					class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||||||
|       <label for="enabled" class="ml-1 font-medium text-gray-700" | 				/> | ||||||
|         >{$_("enabled")}</label | 				{$_("this-scanstation-is")} | ||||||
|       > | 				{#if editable.enabled}{$_("enabled")}{:else}{$_("disabled")}{/if} | ||||||
|       <br /> | 			</p> | ||||||
|       <p class="text-gray-500"> | 		</div> | ||||||
|         <input | 	</section> | ||||||
|           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-scanstation-is")} |  | ||||||
|         {#if editable.enabled}{$_("enabled")}{:else}{$_("disabled")}{/if} |  | ||||||
|       </p> |  | ||||||
|     </div> |  | ||||||
|   </section> |  | ||||||
| {:catch error} | {:catch error} | ||||||
|   <PromiseError {error} /> | 	<PromiseError {error} /> | ||||||
| {/await} | {/await} | ||||||
|   | |||||||
| @@ -1,44 +1,229 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|   import store from "../../store"; | 	import store from "../../store"; | ||||||
|   import AddScanStationModal from "./AddScanStationModal.svelte"; | 	import { ScanStationService } from "@odit/lfk-client-js"; | ||||||
|   import CopyScanStationTokenModal from "./CopyScanStationTokenModal.svelte"; | 	import AddScanStationModal from "./AddScanStationModal.svelte"; | ||||||
|   import ScanStationsOverview from "./ScanStationsOverview.svelte"; | 	import CopyScanStationTokenModal from "./CopyScanStationTokenModal.svelte"; | ||||||
|   export let modal_open = false; | 	import ScanStationsEmptyState from "./ScanStationsEmptyState.svelte"; | ||||||
|   export let copy_modal_open = false; | 	import ConfirmScanStationDeletion from "./ConfirmScanStationDeletion.svelte"; | ||||||
|   export let new_station = {}; | 	import toast from "svelte-french-toast"; | ||||||
|   let current_stations = []; | 	// | ||||||
|  | 	export let modal_open = false; | ||||||
|  | 	export let copy_modal_open = false; | ||||||
|  | 	export let new_station = {}; | ||||||
|  | 	// | ||||||
|  | 	const promise = ScanStationService.scanStationControllerGetAll().then( | ||||||
|  | 		(result) => { | ||||||
|  | 			current_stations = result; | ||||||
|  | 		} | ||||||
|  | 	); | ||||||
|  | 	$: searchvalue = ""; | ||||||
|  | 	$: active_deletes = []; | ||||||
|  | 	let delete_station = {}; | ||||||
|  | 	let current_stations = []; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <section class="container p-5"> | <section class="container p-5"> | ||||||
|   <span class="mb-1 text-3xl font-extrabold leading-tight"> | 	<h4 class="mb-1 text-3xl font-extrabold leading-tight"> | ||||||
|     {$_("scanstations")} | 		{$_("scanstations")} | ||||||
|     {#if store.state.jwtinfo.userdetails.permissions.includes("STATION:CREATE")} | 	</h4> | ||||||
|       <button | 	{#if store.state.jwtinfo.userdetails.permissions.includes("STATION:CREATE")} | ||||||
|         on:click={() => { | 		<button | ||||||
|           modal_open = true; | 			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" | 			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:w-auto sm:text-sm" | ||||||
|         {$_("create-a-new-scanstation")} | 		> | ||||||
|       </button> | 			{$_("create-a-new-scanstation")} | ||||||
|     {/if} | 		</button> | ||||||
|   </span> | 	{/if} | ||||||
|   <ScanStationsOverview | 	<ConfirmScanStationDeletion | ||||||
|     bind:current_stations | 		on:cancelDelete={(event) => { | ||||||
|     bind:modal_open | 			modal_open = false; | ||||||
|     bind:new_station | 			active_deletes[event.detail.id] = false; | ||||||
|     bind:copy_modal_open | 		}} | ||||||
|   /> | 		bind:modal_open | ||||||
|  | 		bind:delete_station | ||||||
|  | 	/> | ||||||
|  | 	{#if store.state.jwtinfo.userdetails.permissions.includes("STATION:GET")} | ||||||
|  | 		{#await promise} | ||||||
|  | 			<div | ||||||
|  | 				class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" | ||||||
|  | 				role="alert" | ||||||
|  | 			> | ||||||
|  | 				<p class="font-bold">{$_("scanstations-are-being-loaded")}</p> | ||||||
|  | 				<p class="text-sm">{$_("this-might-take-a-moment")}</p> | ||||||
|  | 			</div> | ||||||
|  | 		{:then} | ||||||
|  | 			{#if current_stations.length === 0} | ||||||
|  | 				<ScanStationsEmptyState /> | ||||||
|  | 			{:else} | ||||||
|  | 				<input | ||||||
|  | 					type="search" | ||||||
|  | 					bind:value={searchvalue} | ||||||
|  | 					placeholder={$_("datatable.search")} | ||||||
|  | 					aria-label={$_("datatable.search")} | ||||||
|  | 					class="mb-2 w-full sm:w-auto mt-1 sm:mt-0 p-2 rounded-md border" | ||||||
|  | 				/> | ||||||
|  | 				<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 class="odd:bg-white even:bg-gray-100"> | ||||||
|  | 								<th | ||||||
|  | 									scope="col" | ||||||
|  | 									class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|  | 								> | ||||||
|  | 									{$_("track")} | ||||||
|  | 								</th> | ||||||
|  | 								<th | ||||||
|  | 									scope="col" | ||||||
|  | 									class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|  | 								> | ||||||
|  | 									{$_("description")} | ||||||
|  | 								</th> | ||||||
|  | 								<th | ||||||
|  | 									scope="col" | ||||||
|  | 									class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" | ||||||
|  | 								> | ||||||
|  | 									{$_("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_stations as s} | ||||||
|  | 								{#if Object.values(s) | ||||||
|  | 									.toString() | ||||||
|  | 									.toLowerCase() | ||||||
|  | 									.includes(searchvalue)} | ||||||
|  | 									<tr | ||||||
|  | 										class="odd:bg-white even:bg-gray-100" | ||||||
|  | 										data-rowid="station_{s.id}" | ||||||
|  | 									> | ||||||
|  | 										<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  | 											<div class="flex items-center"> | ||||||
|  | 												<div class="ml-4"> | ||||||
|  | 													<div class="text-sm font-medium text-gray-900"> | ||||||
|  | 														<a | ||||||
|  | 															href="../tracks" | ||||||
|  | 															class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current" | ||||||
|  | 														> | ||||||
|  | 															{s.track.name || s.track.distance + "m"}</a | ||||||
|  | 														> | ||||||
|  | 													</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"> | ||||||
|  | 														{s.description} | ||||||
|  | 													</div> | ||||||
|  | 												</div> | ||||||
|  | 											</div> | ||||||
|  | 										</td> | ||||||
|  | 										<td class="px-6 py-4 whitespace-nowrap"> | ||||||
|  | 											<div class="flex items-center"> | ||||||
|  | 												{#if s.enabled} | ||||||
|  | 													<span | ||||||
|  | 														class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-green-100 text-green-800" | ||||||
|  | 														>{$_("active")}</span | ||||||
|  | 													> | ||||||
|  | 												{:else} | ||||||
|  | 													<span | ||||||
|  | 														class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-red-100 text-red-800" | ||||||
|  | 														>{$_("inactive")}</span | ||||||
|  | 													> | ||||||
|  | 												{/if} | ||||||
|  | 											</div> | ||||||
|  | 										</td> | ||||||
|  | 										{#if active_deletes[s.id] === true} | ||||||
|  | 											<td | ||||||
|  | 												class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium" | ||||||
|  | 											> | ||||||
|  | 												<button | ||||||
|  | 													on:click={() => { | ||||||
|  | 														active_deletes[s.id] = false; | ||||||
|  | 													}} | ||||||
|  | 													tabindex="0" | ||||||
|  | 													class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer" | ||||||
|  | 													>{$_("cancel-delete")}</button | ||||||
|  | 												> | ||||||
|  | 												<button | ||||||
|  | 													on:click={() => { | ||||||
|  | 														ScanStationService.scanStationControllerRemove( | ||||||
|  | 															s.id, | ||||||
|  | 															false | ||||||
|  | 														) | ||||||
|  | 															.then((resp) => { | ||||||
|  | 																current_stations = current_stations.filter( | ||||||
|  | 																	(obj) => obj.id !== s.id | ||||||
|  | 																); | ||||||
|  | 																toast.success($_("station-deleted")); | ||||||
|  | 															}) | ||||||
|  | 															.catch((err) => { | ||||||
|  | 																modal_open = true; | ||||||
|  | 																delete_station = s; | ||||||
|  | 															}); | ||||||
|  | 													}} | ||||||
|  | 													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="/scanstations/{s.id}" | ||||||
|  | 													class="text-indigo-600 hover:text-indigo-900" | ||||||
|  | 													>{$_("details")}</a | ||||||
|  | 												> | ||||||
|  | 												{#if store.state.jwtinfo.userdetails.permissions.includes("STATION:DELETE")} | ||||||
|  | 													<button | ||||||
|  | 														on:click={() => { | ||||||
|  | 															active_deletes[s.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} | ||||||
| </section> | </section> | ||||||
|  |  | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes("STATION:CREATE")} | {#if store.state.jwtinfo.userdetails.permissions.includes("STATION:CREATE")} | ||||||
|   <AddScanStationModal | 	<AddScanStationModal | ||||||
|     bind:modal_open | 		bind:modal_open | ||||||
|     bind:current_stations | 		bind:current_stations | ||||||
|     bind:new_station | 		bind:new_station | ||||||
|     bind:copy_modal_open | 		bind:copy_modal_open | ||||||
|   /> | 	/> | ||||||
|   <CopyScanStationTokenModal bind:copy_modal_open bind:new_station /> | 	<CopyScanStationTokenModal bind:copy_modal_open bind:new_station /> | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -1,195 +0,0 @@ | |||||||
| <script> |  | ||||||
|   import { _ } from "svelte-i18n"; |  | ||||||
|   import { ScanStationService } from "@odit/lfk-client-js"; |  | ||||||
|   const promise = ScanStationService.scanStationControllerGetAll().then( |  | ||||||
|     (result) => { |  | ||||||
|       current_stations = result; |  | ||||||
|     } |  | ||||||
|   ); |  | ||||||
|   import store from "../../store"; |  | ||||||
|   import ScanStationsEmptyState from "./ScanStationsEmptyState.svelte"; |  | ||||||
|   import ConfirmScanStationDeletion from "./ConfirmScanStationDeletion.svelte"; |  | ||||||
|   import toast from "svelte-french-toast"; |  | ||||||
|   $: searchvalue = ""; |  | ||||||
|   $: active_deletes = []; |  | ||||||
|   let delete_station = {}; |  | ||||||
|   let modal_open = false; |  | ||||||
|   export let current_stations = []; |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <ConfirmScanStationDeletion |  | ||||||
|   on:cancelDelete={(event) => { |  | ||||||
|     modal_open = false; |  | ||||||
|     active_deletes[event.detail.id] = false; |  | ||||||
|   }} |  | ||||||
|   bind:modal_open |  | ||||||
|   bind:delete_station |  | ||||||
| /> |  | ||||||
| {#if store.state.jwtinfo.userdetails.permissions.includes("STATION:GET")} |  | ||||||
|   {#await promise} |  | ||||||
|     <div |  | ||||||
|       class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" |  | ||||||
|       role="alert" |  | ||||||
|     > |  | ||||||
|       <p class="font-bold">{$_("scanstations-are-being-loaded")}</p> |  | ||||||
|       <p class="text-sm">{$_("this-might-take-a-moment")}</p> |  | ||||||
|     </div> |  | ||||||
|   {:then} |  | ||||||
|     {#if current_stations.length === 0} |  | ||||||
|       <ScanStationsEmptyState /> |  | ||||||
|     {:else} |  | ||||||
|       <input |  | ||||||
|         type="search" |  | ||||||
|         bind:value={searchvalue} |  | ||||||
|         placeholder={$_("datatable.search")} |  | ||||||
|         aria-label={$_("datatable.search")} |  | ||||||
|         class="mb-4" |  | ||||||
|       /> |  | ||||||
|       <div |  | ||||||
|         class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll" |  | ||||||
|       > |  | ||||||
|         <table class="divide-y divide-gray-200 w-full"> |  | ||||||
|           <thead class="bg-gray-50"> |  | ||||||
|             <tr class="odd:bg-white even:bg-gray-100"> |  | ||||||
|               <th |  | ||||||
|                 scope="col" |  | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" |  | ||||||
|               > |  | ||||||
|                 {$_("track")} |  | ||||||
|               </th> |  | ||||||
|               <th |  | ||||||
|                 scope="col" |  | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" |  | ||||||
|               > |  | ||||||
|                 {$_("description")} |  | ||||||
|               </th> |  | ||||||
|               <th |  | ||||||
|                 scope="col" |  | ||||||
|                 class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" |  | ||||||
|               > |  | ||||||
|                 {$_("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_stations as s} |  | ||||||
|               {#if Object.values(s) |  | ||||||
|                 .toString() |  | ||||||
|                 .toLowerCase() |  | ||||||
|                 .includes(searchvalue)} |  | ||||||
|                 <tr |  | ||||||
|                   class="odd:bg-white even:bg-gray-100" |  | ||||||
|                   data-rowid="station_{s.id}" |  | ||||||
|                 > |  | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                     <div class="flex items-center"> |  | ||||||
|                       <div class="ml-4"> |  | ||||||
|                         <div class="text-sm font-medium text-gray-900"> |  | ||||||
|                           <a |  | ||||||
|                             href="../tracks" |  | ||||||
|                             class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800" |  | ||||||
|                           > |  | ||||||
|                             {s.track.name || s.track.distance + "m"}</a |  | ||||||
|                           > |  | ||||||
|                         </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"> |  | ||||||
|                           {s.description} |  | ||||||
|                         </div> |  | ||||||
|                       </div> |  | ||||||
|                     </div> |  | ||||||
|                   </td> |  | ||||||
|                   <td class="px-6 py-4 whitespace-nowrap"> |  | ||||||
|                     <div class="flex items-center"> |  | ||||||
|                       {#if s.enabled} |  | ||||||
|                         <span |  | ||||||
|                           class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800" |  | ||||||
|                           >{$_("active")}</span |  | ||||||
|                         > |  | ||||||
|                       {:else} |  | ||||||
|                         <span |  | ||||||
|                           class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800" |  | ||||||
|                           >{$_("inactive")}</span |  | ||||||
|                         > |  | ||||||
|                       {/if} |  | ||||||
|                     </div> |  | ||||||
|                   </td> |  | ||||||
|                   {#if active_deletes[s.id] === true} |  | ||||||
|                     <td |  | ||||||
|                       class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium" |  | ||||||
|                     > |  | ||||||
|                       <button |  | ||||||
|                         on:click={() => { |  | ||||||
|                           active_deletes[s.id] = false; |  | ||||||
|                         }} |  | ||||||
|                         tabindex="0" |  | ||||||
|                         class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer" |  | ||||||
|                         >{$_("cancel-delete")}</button |  | ||||||
|                       > |  | ||||||
|                       <button |  | ||||||
|                         on:click={() => { |  | ||||||
|                           ScanStationService.scanStationControllerRemove( |  | ||||||
|                             s.id, |  | ||||||
|                             false |  | ||||||
|                           ) |  | ||||||
|                             .then((resp) => { |  | ||||||
|                               current_stations = current_stations.filter( |  | ||||||
|                                 (obj) => obj.id !== s.id |  | ||||||
|                               ); |  | ||||||
|                               toast($_("station-deleted")); |  | ||||||
|                             }) |  | ||||||
|                             .catch((err) => { |  | ||||||
|                               modal_open = true; |  | ||||||
|                               delete_station = s; |  | ||||||
|                             }); |  | ||||||
|                         }} |  | ||||||
|                         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="/scanstations/{s.id}" |  | ||||||
|                         class="text-indigo-600 hover:text-indigo-900" |  | ||||||
|                         >{$_("details")}</a |  | ||||||
|                       > |  | ||||||
|                       {#if store.state.jwtinfo.userdetails.permissions.includes("STATION:DELETE")} |  | ||||||
|                         <button |  | ||||||
|                           on:click={() => { |  | ||||||
|                             active_deletes[s.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} |  | ||||||
| @@ -25,12 +25,12 @@ | |||||||
|  |  | ||||||
| {#if modal_open} | {#if modal_open} | ||||||
|   <div |   <div | ||||||
|     class="fixed z-10 inset-0 overflow-y-auto" |     class="fixed z-10 inset-0 overflow-y-hidden" | ||||||
|     use:clickOutside |     use:clickOutside | ||||||
|     on:click_outside={cancelDelete} |     on:click_outside={cancelDelete} | ||||||
|   > |   > | ||||||
|     <div |     <div | ||||||
|       class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" |       class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4" | ||||||
|     > |     > | ||||||
|       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |       <div class="fixed inset-0 transition-opacity" aria-hidden="true"> | ||||||
|         <div |         <div | ||||||
| @@ -43,15 +43,15 @@ | |||||||
|         aria-hidden="true">​</span |         aria-hidden="true">​</span | ||||||
|       > |       > | ||||||
|       <div |       <div | ||||||
|         class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" |         class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]" | ||||||
|         role="dialog" |         role="dialog" | ||||||
|         aria-modal="true" |         aria-modal="true" | ||||||
|         aria-labelledby="modal-headline" |         aria-labelledby="modal-headline" | ||||||
|       > |       > | ||||||
|         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> |         <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl"> | ||||||
|           <div class="sm:flex sm:items-start"> |           <div class=""> | ||||||
|             <div |             <div | ||||||
|               class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" |               class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" | ||||||
|             > |             > | ||||||
|               <svg |               <svg | ||||||
|                 class="h-6 w-6 text-blue-600" |                 class="h-6 w-6 text-blue-600" | ||||||
| @@ -63,11 +63,11 @@ | |||||||
|                 /></svg |                 /></svg | ||||||
|               > |               > | ||||||
|             </div> |             </div> | ||||||
|             <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> |             <div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto"> | ||||||
|               <h3 class="text-lg leading-6 font-medium text-gray-900"> |               <h3 class="text-lg leading-6 font-medium text-gray-900"> | ||||||
|                 {$_("attention")} |                 {$_("attention")} | ||||||
|               </h3> |               </h3> | ||||||
|               <div class="mt-2 mb-6"> |               <div class="mb-6"> | ||||||
|                 <p class="text-sm text-gray-500"> |                 <p class="text-sm text-gray-500"> | ||||||
|                   {$_("do-you-really-want-to-delete-your-profile")} |                   {$_("do-you-really-want-to-delete-your-profile")} | ||||||
|                   <br /> |                   <br /> | ||||||
| @@ -81,18 +81,18 @@ | |||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> |         <div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> | ||||||
|           <button |           <button | ||||||
|             on:click={deleteMe} |             on:click={deleteMe} | ||||||
|             type="button" |             type="button" | ||||||
|             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500" | ||||||
|           > |           > | ||||||
|             {$_("confirm-delete-my-user-profile")} |             {$_("confirm-delete-my-user-profile")} | ||||||
|           </button> |           </button> | ||||||
|           <button |           <button | ||||||
|             on:click={cancelDelete} |             on:click={cancelDelete} | ||||||
|             type="button" |             type="button" | ||||||
|             class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm" |             class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" | ||||||
|           > |           > | ||||||
|             {$_("cancel-keep-my-profile")} |             {$_("cancel-keep-my-profile")} | ||||||
|           </button> |           </button> | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
|   import { _ } from "svelte-i18n"; |   import { _ } from "svelte-i18n"; | ||||||
|   import isEmail from "validator/es/lib/isEmail"; |   import isEmail from "validator/es/lib/isEmail"; | ||||||
|   import { MeService } from "@odit/lfk-client-js"; |   import { MeService } from "@odit/lfk-client-js"; | ||||||
|  |   import toast from 'svelte-french-toast' | ||||||
|  |  | ||||||
|   import ConfirmProfileDeletion from "./ConfirmProfileDeletion.svelte"; |   import ConfirmProfileDeletion from "./ConfirmProfileDeletion.svelte"; | ||||||
|   import PasswordStrength, { |   import PasswordStrength, { | ||||||
| @@ -61,21 +62,13 @@ | |||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <ConfirmProfileDeletion bind:modal_open bind:delete_triggered /> | <ConfirmProfileDeletion bind:modal_open bind:delete_triggered /> | ||||||
| <div class="pt-12 px-4 sm:px-6 lg:px-8 lg:pt-20 bg-gray-900 pb-12"> |  | ||||||
|   <div class="text-center mb-8"> |  | ||||||
|     <h1 |  | ||||||
|       class="mt-9 font-display text-4xl leading-none font-semibold text-white sm:text-5xl lg:text-6xl" |  | ||||||
|     > |  | ||||||
|       🔨<br />{$_("settings")} |  | ||||||
|     </h1> |  | ||||||
|   </div> |  | ||||||
| </div> |  | ||||||
| <div class="pt-0 pb-16 bg-gray-50 overflow-hidden lg:pt-12 lg:py-24"> | <div class="pt-0 pb-16 bg-gray-50 overflow-hidden lg:pt-12 lg:py-24"> | ||||||
|   <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8"> |   <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8"> | ||||||
|  |     <span class="text-3xl font-bold">{$_("settings")}</span> | ||||||
|     <div> |     <div> | ||||||
|       <div class="md:grid md:grid-cols-3 md:gap-6"> |       <div class="md:grid md:grid-cols-3 md:gap-2 lg:gap-6"> | ||||||
|         <div class="md:col-span-1"> |         <div class="md:col-span-1"> | ||||||
|           <div class="px-4 sm:px-0"> |           <div class="sm:px-0"> | ||||||
|             <h3 class="text-lg font-medium leading-6 text-gray-900"> |             <h3 class="text-lg font-medium leading-6 text-gray-900"> | ||||||
|               {$_("profile")} |               {$_("profile")} | ||||||
|             </h3> |             </h3> | ||||||
| @@ -90,8 +83,8 @@ | |||||||
|           <div class="mt-5 md:mt-0 md:col-span-2"> |           <div class="mt-5 md:mt-0 md:col-span-2"> | ||||||
|             <div class="shadow sm:rounded-md sm:overflow-hidden"> |             <div class="shadow sm:rounded-md sm:overflow-hidden"> | ||||||
|               <div class="px-4 py-5 bg-white space-y-6 sm:p-6"> |               <div class="px-4 py-5 bg-white space-y-6 sm:p-6"> | ||||||
|                 <div class="text-sm w-full"> |                 <div class="text-sm w-full mt-2"> | ||||||
|                   <label for="username" class="font-medium text-gray-700" |                   <label for="username" class="font-semibold text-gray-700" | ||||||
|                     >{$_("username")}</label |                     >{$_("username")}</label | ||||||
|                   > |                   > | ||||||
|                   <input |                   <input | ||||||
| @@ -100,11 +93,11 @@ | |||||||
|                     type="text" |                     type="text" | ||||||
|                     bind:value={editable.username} |                     bind:value={editable.username} | ||||||
|                     name="username" |                     name="username" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="text-sm w-full"> |                 <div class="text-sm w-full mt-2"> | ||||||
|                   <label for="email" class="font-medium text-gray-700" |                   <label for="email" class="font-semibold text-gray-700" | ||||||
|                     >{$_("e-mail-adress")}</label |                     >{$_("e-mail-adress")}</label | ||||||
|                   > |                   > | ||||||
|                   <input |                   <input | ||||||
| @@ -113,7 +106,7 @@ | |||||||
|                     type="email" |                     type="email" | ||||||
|                     bind:value={editable.email} |                     bind:value={editable.email} | ||||||
|                     name="email" |                     name="email" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                 </div> |                 </div> | ||||||
|                 {#if !isEmail(editable.email)} |                 {#if !isEmail(editable.email)} | ||||||
| @@ -122,8 +115,8 @@ | |||||||
|                     >{$_("valid-email-is-required")}</span |                     >{$_("valid-email-is-required")}</span | ||||||
|                   > |                   > | ||||||
|                 {/if} |                 {/if} | ||||||
|                 <div class="text-sm w-full"> |                 <div class="text-sm w-full mt-2"> | ||||||
|                   <label for="firstname" class="font-medium text-gray-700" |                   <label for="firstname" class="font-semibold text-gray-700" | ||||||
|                     >{$_("first-name")}</label |                     >{$_("first-name")}</label | ||||||
|                   > |                   > | ||||||
|                   <input |                   <input | ||||||
| @@ -132,11 +125,11 @@ | |||||||
|                     type="text" |                     type="text" | ||||||
|                     bind:value={editable.firstname} |                     bind:value={editable.firstname} | ||||||
|                     name="firstname" |                     name="firstname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                 </div> |                 </div> | ||||||
|                 <!-- <div class="text-sm w-full"> |                 <!-- <div class="text-sm w-full mt-2"> | ||||||
|                   <label for="middlename" class="font-medium text-gray-700" |                   <label for="middlename" class="font-semibold text-gray-700" | ||||||
|                     >{$_("middle-name")}</label |                     >{$_("middle-name")}</label | ||||||
|                   > |                   > | ||||||
|                   <input |                   <input | ||||||
| @@ -145,11 +138,11 @@ | |||||||
|                     type="text" |                     type="text" | ||||||
|                     bind:value={editable.middlename} |                     bind:value={editable.middlename} | ||||||
|                     name="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" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                 </div> --> |                 </div> --> | ||||||
|                 <div class="text-sm w-full"> |                 <div class="text-sm w-full mt-2"> | ||||||
|                   <label for="lastname" class="font-medium text-gray-700" |                   <label for="lastname" class="font-semibold text-gray-700" | ||||||
|                     >{$_("last-name")}</label |                     >{$_("last-name")}</label | ||||||
|                   > |                   > | ||||||
|                   <input |                   <input | ||||||
| @@ -158,7 +151,7 @@ | |||||||
|                     type="text" |                     type="text" | ||||||
|                     bind:value={editable.lastname} |                     bind:value={editable.lastname} | ||||||
|                     name="lastname" |                     name="lastname" | ||||||
|                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" |                     class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||||
|                   /> |                   /> | ||||||
|                 </div> |                 </div> | ||||||
|               </div> |               </div> | ||||||
| @@ -168,7 +161,7 @@ | |||||||
|                   disabled={!save_enabled} |                   disabled={!save_enabled} | ||||||
|                   class:opacity-50={!save_enabled} |                   class:opacity-50={!save_enabled} | ||||||
|                   on:click={submit} |                   on:click={submit} | ||||||
|                   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" |                   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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|                 > |                 > | ||||||
|                   {$_("save-changes")} |                   {$_("save-changes")} | ||||||
|                 </button> |                 </button> | ||||||
| @@ -181,9 +174,9 @@ | |||||||
|   </div> |   </div> | ||||||
|   <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8"> |   <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8"> | ||||||
|     <div> |     <div> | ||||||
|       <div class="md:grid md:grid-cols-3 md:gap-6"> |       <div class="md:grid md:grid-cols-3 md:gap-2 lg:gap-6"> | ||||||
|         <div class="md:col-span-1"> |         <div class="md:col-span-1"> | ||||||
|           <div class="px-4 sm:px-0"> |           <div class="sm:px-0"> | ||||||
|             <h3 class="text-lg font-medium leading-6 text-gray-900"> |             <h3 class="text-lg font-medium leading-6 text-gray-900"> | ||||||
|               {$_("password")} |               {$_("password")} | ||||||
|             </h3> |             </h3> | ||||||
| @@ -198,7 +191,7 @@ | |||||||
|           <div class="mt-5 md:mt-0 md:col-span-2"> |           <div class="mt-5 md:mt-0 md:col-span-2"> | ||||||
|             <div class="shadow sm:rounded-md sm:overflow-hidden"> |             <div class="shadow sm:rounded-md sm:overflow-hidden"> | ||||||
|               <div class="px-4 py-3 bg-gray-50 text-left sm:px-6"> |               <div class="px-4 py-3 bg-gray-50 text-left sm:px-6"> | ||||||
|                 <label for="new_password" class="font-medium text-gray-700" |                 <label for="new_password" class="font-semibold text-gray-700" | ||||||
|                   >{$_("new-password")}</label |                   >{$_("new-password")}</label | ||||||
|                 > |                 > | ||||||
|                 <div class="-mt-px relative"> |                 <div class="-mt-px relative"> | ||||||
| @@ -211,7 +204,7 @@ | |||||||
|                     placeholder={$_("password")} |                     placeholder={$_("password")} | ||||||
|                   /> |                   /> | ||||||
|                 </div> |                 </div> | ||||||
|                 <label for="new_password" class="font-medium text-gray-700" |                 <label for="new_password" class="font-semibold text-gray-700" | ||||||
|                   >{$_("confirm-the-new-password")}</label |                   >{$_("confirm-the-new-password")}</label | ||||||
|                 > |                 > | ||||||
|                 <div class="-mt-px relative"> |                 <div class="-mt-px relative"> | ||||||
| @@ -232,7 +225,7 @@ | |||||||
|                   disabled={!update_password_enabled} |                   disabled={!update_password_enabled} | ||||||
|                   class:opacity-50={!update_password_enabled} |                   class:opacity-50={!update_password_enabled} | ||||||
|                   on:click={changePassword} |                   on:click={changePassword} | ||||||
|                   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" |                   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:w-auto sm:text-sm mb-1 lg:mb-0" | ||||||
|                 > |                 > | ||||||
|                   {$_("update-password")} |                   {$_("update-password")} | ||||||
|                 </button> |                 </button> | ||||||
| @@ -252,9 +245,9 @@ | |||||||
|   </div> |   </div> | ||||||
|   <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8"> |   <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8"> | ||||||
|     <div> |     <div> | ||||||
|       <div class="md:grid md:grid-cols-3 md:gap-6"> |       <div class="md:grid md:grid-cols-3 md:gap-2 lg:gap-6"> | ||||||
|         <div class="md:col-span-1"> |         <div class="md:col-span-1"> | ||||||
|           <div class="px-4 sm:px-0"> |           <div class="sm:px-0"> | ||||||
|             <h3 class="text-lg font-medium leading-6 text-gray-900"> |             <h3 class="text-lg font-medium leading-6 text-gray-900"> | ||||||
|               {$_("danger-zone")} |               {$_("danger-zone")} | ||||||
|             </h3> |             </h3> | ||||||
| @@ -275,7 +268,7 @@ | |||||||
|                       on:click={() => { |                       on:click={() => { | ||||||
|                         modal_open = true; |                         modal_open = true; | ||||||
|                       }} |                       }} | ||||||
|                       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:" |                       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" | ||||||
|                       >{$_("confirm-deletion")}</button |                       >{$_("confirm-deletion")}</button | ||||||
|                     > |                     > | ||||||
|                     <button |                     <button | ||||||
| @@ -292,7 +285,7 @@ | |||||||
|                         delete_triggered = true; |                         delete_triggered = true; | ||||||
|                       }} |                       }} | ||||||
|                       type="button" |                       type="button" | ||||||
|                       class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:" |                       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" | ||||||
|                       >{$_("delete-profile")}</button |                       >{$_("delete-profile")}</button | ||||||
|                     > |                     > | ||||||
|                   {/if} |                   {/if} | ||||||
|   | |||||||
| @@ -1,26 +1,26 @@ | |||||||
| <script> | <script> | ||||||
|   import { _ } from "svelte-i18n"; | 	import { _ } from "svelte-i18n"; | ||||||
|  |  | ||||||
|   export let detailsLink; | 	export let detailsLink = null; | ||||||
|   export let detailsAction; | 	export let detailsAction = null; | ||||||
|   export let deleteEnabled; | 	export let deleteEnabled; | ||||||
|   export let deleteAction; | 	export let deleteAction; | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| {#if detailsLink} | {#if detailsLink} | ||||||
|   <a href={detailsLink} class="text-indigo-600 hover:text-indigo-900" | 	<a href={detailsLink} class="text-indigo-600 hover:text-indigo-900" | ||||||
|     >{$_("details")}</a | 		>{$_("details")}</a | ||||||
|   > | 	> | ||||||
| {:else if detailsAction} | {:else if detailsAction} | ||||||
|   <button on:click={detailsAction} class="text-indigo-600 hover:text-indigo-900" | 	<button on:click={detailsAction} class="text-indigo-600 hover:text-indigo-900" | ||||||
|     >{$_("details")}</button | 		>{$_("details")}</button | ||||||
|   > | 	> | ||||||
| {/if} | {/if} | ||||||
| {#if deleteEnabled} | {#if deleteEnabled} | ||||||
|   <button | 	<button | ||||||
|     tabindex="0" | 		tabindex="0" | ||||||
|     on:click={deleteAction} | 		on:click={deleteAction} | ||||||
|     class="ml-4 text-red-600 hover:text-red-900 cursor-pointer" | 		class="ml-4 text-red-600 hover:text-red-900 cursor-pointer" | ||||||
|     >{$_("delete")}</button | 		>{$_("delete")}</button | ||||||
|   > | 	> | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user