Compare commits
	
		
			8 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2139b197ba | |||
| 4e1a944a2d | |||
| e3c6d5a5c0 | |||
| 8c3f0092d2 | |||
| 6fad04c862 | |||
| 838dcbfd7e | |||
| f5df252857 | |||
| 285fc91c66 | 
							
								
								
									
										23
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -2,9 +2,32 @@ | ||||
|  | ||||
| All notable changes to this project will be documented in this file. Dates are displayed in UTC. | ||||
|  | ||||
| #### [1.13.3](https://git.odit.services/lfk/frontend/compare/1.13.2...1.13.3) | ||||
|  | ||||
| - Refactor code structure for improved readability and maintainability [`e3c6d5a`](https://git.odit.services/lfk/frontend/commit/e3c6d5a5c0eaac2c91432b0be37d6fa11e57f644) | ||||
| - refactor(donation): Refactor donor selection and add new donor creation functionality [`8c3f009`](https://git.odit.services/lfk/frontend/commit/8c3f0092d2735b1c85976f4e6955780b1035f68a) | ||||
| - fix(donation): Ensure all selections are cleared on reset [`4e1a944`](https://git.odit.services/lfk/frontend/commit/4e1a944a2d7d0d0666fb8d2181a9941d0f11957f) | ||||
|  | ||||
| #### [1.13.2](https://git.odit.services/lfk/frontend/compare/1.13.1...1.13.2) | ||||
|  | ||||
| > 16 May 2025 | ||||
|  | ||||
| - chore(release): 1.13.2 [`6fad04c`](https://git.odit.services/lfk/frontend/commit/6fad04c86249613dacfe2bc75362cb32d109573d) | ||||
| - feat(dashboard): Add permission checks for scan and donation creation links [`838dcbf`](https://git.odit.services/lfk/frontend/commit/838dcbfd7e0c09e8cf61a04952475934ad1e3b86) | ||||
|  | ||||
| #### [1.13.1](https://git.odit.services/lfk/frontend/compare/1.13.0...1.13.1) | ||||
|  | ||||
| > 16 May 2025 | ||||
|  | ||||
| - chore(release): 1.13.1 [`f5df252`](https://git.odit.services/lfk/frontend/commit/f5df252857f20f8426b8ca566b9bb3ec50331880) | ||||
| - feat(tools): Remove unnecessary validation display in donation creation [`285fc91`](https://git.odit.services/lfk/frontend/commit/285fc91c66d03aaa861da549cb739c3698beb892) | ||||
|  | ||||
| #### [1.13.0](https://git.odit.services/lfk/frontend/compare/1.12.8...1.13.0) | ||||
|  | ||||
| > 16 May 2025 | ||||
|  | ||||
| - feat(tools): Basic mobile scanner [`500886e`](https://git.odit.services/lfk/frontend/commit/500886e4106f4b53fbc40fb0fa15653f574c8328) | ||||
| - chore(release): 1.13.0 [`d95b6cf`](https://git.odit.services/lfk/frontend/commit/d95b6cf5894dd0b487353f36c9f3a436066fd4ef) | ||||
| - feat(tools): Added tool for fast sponsoring creation [`51ba1c8`](https://git.odit.services/lfk/frontend/commit/51ba1c852cad6243e935409da1eacecc5dcfa5fa) | ||||
| - feat(dev): Enable devserver with https-support to circumvent ios https requirements for camera access [`25c38ea`](https://git.odit.services/lfk/frontend/commit/25c38ea3812a529a90294ff8834bdb65c487f8c4) | ||||
| - feat(tools): Remove requirement for ten-diget codes [`80ca7aa`](https://git.odit.services/lfk/frontend/commit/80ca7aa08bdd44591e2d3efaa8e59dd4db5c864e) | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
|  | ||||
|   <body> | ||||
|     <span style="display: none; visibility: hidden" id="buildinfo" | ||||
|       >RELEASE_INFO-1.13.0-RELEASE_INFO</span | ||||
|       >RELEASE_INFO-1.13.3-RELEASE_INFO</span | ||||
|     > | ||||
|     <noscript>You need to enable JavaScript to run this app.</noscript> | ||||
|     <script src="/env.js"></script> | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "@odit/lfk-frontend", | ||||
|   "version": "1.13.0", | ||||
|   "version": "1.13.3", | ||||
|   "type": "module", | ||||
|   "scripts": { | ||||
|     "i18n-order": "node order.js", | ||||
|   | ||||
| @@ -85,6 +85,8 @@ | ||||
|  | ||||
|           <span>{$_("card-replacement-menu")}</span> | ||||
|         </a> | ||||
|         {/if} | ||||
|       {#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:CREATE")} | ||||
|         <a | ||||
|           class:activenav={$router.path.includes("/tools/scanclient/")} | ||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||
| @@ -105,6 +107,8 @@ | ||||
|  | ||||
|           <span>{$_("scanclient")}</span> | ||||
|         </a> | ||||
|         {/if} | ||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:CREATE")} | ||||
|         <a | ||||
|           class:activenav={$router.path.includes("/tools/donationcreate/")} | ||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||
| @@ -125,9 +129,11 @@ | ||||
|  | ||||
|           <span>{$_("donation-quick-add")}</span> | ||||
|         </a> | ||||
|         {/if} | ||||
|         <h2 class="px-4 py-2 text-xs font-semibold text-gray-600 uppercase"> | ||||
|           {$_("management")} | ||||
|         </h2> | ||||
|         {#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:GET")} | ||||
|         <a | ||||
|           class:activenav={$router.path.includes("/runners/")} | ||||
|           class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold" | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
|     DonorService, | ||||
|     RunnerService, | ||||
|   } from "@odit/lfk-client-js"; | ||||
|   import Svelecte from "svelecte"; | ||||
|   import Select from "svelte-select"; | ||||
|   import toast from "svelte-french-toast"; | ||||
|  | ||||
| @@ -21,8 +20,9 @@ | ||||
|     country: "Germany", | ||||
|   }; | ||||
|   let amount = 0; | ||||
|   let lastname = ""; | ||||
|   let address_checked = false; | ||||
|   let donor_create_new = false; | ||||
|   let last_created = null; | ||||
|  | ||||
|   RunnerService.runnerControllerGetAll() | ||||
|     .then((val) => { | ||||
| @@ -38,7 +38,7 @@ | ||||
|     DonorService.donorControllerGetAll() | ||||
|       .then((val) => { | ||||
|         donors = val.map((r) => { | ||||
|           return { label: getDonorlabel(r), value: r }; | ||||
|           return { label: getRunnerLabel(r), value: r }; | ||||
|         }); | ||||
|         console.log("refreshed donors"); | ||||
|         setTimeout(() => { | ||||
| @@ -54,8 +54,6 @@ | ||||
|   const getRunnerLabel = (option) => | ||||
|     option.firstname + " " + (option.middlename || "") + " " + option.lastname; | ||||
|  | ||||
|   const getDonorlabel = (option) => `${option.firstname} (${option.lastname})`; | ||||
|  | ||||
|   const filterRunners = (label, filterText, option) => { | ||||
|     if (filterText.startsWith("#")) { | ||||
|       return option.value.id == parseInt(filterText.replace("#", "")); | ||||
| @@ -70,225 +68,284 @@ | ||||
|     runnerinfo = { id: 0, firstname: "", lastname: "" }; | ||||
|     donorinfo = { id: 0, firstname: "", lastname: "" }; | ||||
|     amount = 0; | ||||
|     address_checked = false; | ||||
|     donor_create_new = false; | ||||
|     const clears = document.getElementsByClassName("clearSelect"); | ||||
|     for (let i = 0; i < clears.length; i++) { | ||||
|       clears[i].click(); | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <div class="p-4"> | ||||
|   <h3 class="text-3xl font-bold">{$_("fast_donation_create")}</h3> | ||||
|   <!--  --> | ||||
|   <div class="grid grid-cols-6 gap-4"> | ||||
|     <div class="col-span-2"> | ||||
|       <h4 class="text-xl font-semibold"> | ||||
|         {$_("runner")} | ||||
|       </h4> | ||||
|       <Select | ||||
|         containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||
|         itemFilter={(label, filterText, option) => | ||||
|           filterRunners(label, filterText, option)} | ||||
|         items={runners} | ||||
|         showChevron={true} | ||||
|         placeholder={$_("search-for-runner-by-name-or-id")} | ||||
|         noOptionsMessage={$_("no-runners-found")} | ||||
|         on:select={(selectedValue) => { | ||||
|           runnerinfo = selectedValue.detail.value; | ||||
|         }} | ||||
|         on:clear={() => (runnerinfo.runner = null)} | ||||
|       /> | ||||
|     </div> | ||||
|     <div class="col-span-2"> | ||||
|       <h4 class="text-xl font-semibold"> | ||||
|         {$_("donor")} | ||||
|       </h4> | ||||
|       <div class="mb-2"> | ||||
|         <Svelecte | ||||
|           name="donor_fistname" | ||||
|           placeholder={$_("first-name")} | ||||
|           clearable={true} | ||||
|           options={donors} | ||||
|           keepCreated={false} | ||||
|           creatable={true} | ||||
|           labelField="label" | ||||
|           on:change={(e) => { | ||||
|             if (!e.detail?.value) { | ||||
|               donorinfo = { id: 0, firstname: "", lastname: "" }; | ||||
|               return; | ||||
|             } | ||||
|             if (!e.detail?.$created) { | ||||
|               donorinfo = e.detail.value; | ||||
|               lastname = e.detail.value.lastname; | ||||
|             } else { | ||||
|               console.log("created option", e); | ||||
|               donorinfo.firstname = e.detail.value; | ||||
|             } | ||||
|           }} | ||||
|           class="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-0.5" | ||||
|         /> | ||||
|         <input | ||||
|           autocomplete="off" | ||||
|           placeholder={$_("last-name")} | ||||
|           class:border-red-500={donorinfo.lastname?.length == 0} | ||||
|           class:focus:border-red-500={donorinfo.lastname?.length == 0} | ||||
|           class:focus:ring-red-500={donorinfo.lastname?.length == 0} | ||||
|           bind:value={lastname} | ||||
|           on:input={e => { | ||||
|             donorinfo.lastname = e.target.value; | ||||
|           }} | ||||
|           type="text" | ||||
|           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-neutral-800 rounded-md p-2" | ||||
|         /> | ||||
|       </div> | ||||
|       <div class="flex items-start"> | ||||
|         <div class="flex items-center h-5"> | ||||
|           {#if donorinfo.id == 0} | ||||
|             <input | ||||
|               bind:checked={address_checked} | ||||
|               id="comments" | ||||
|               name="comments" | ||||
|               type="checkbox" | ||||
|               class="focus:ring-indigo-500 size-4 text-indigo-600 border-gray-300 rounded" | ||||
|             /> | ||||
|           {:else} | ||||
|             <input | ||||
|               checked={true} | ||||
|               disabled | ||||
|               id="comments" | ||||
|               name="comments" | ||||
|               type="checkbox" | ||||
|               class="focus:ring-indigo-500 size-4 text-indigo-600 border-gray-300 rounded" | ||||
|             /> | ||||
|           {/if} | ||||
|         </div> | ||||
|         <div class="ml-3 text-sm"> | ||||
|           <label for="comments" class="font-semibold text-gray-700" | ||||
|             >{$_("receipt-needed")}</label | ||||
|           > | ||||
|         </div> | ||||
|       </div> | ||||
|       {#if address_checked} | ||||
|         <div class="col-span-6"> | ||||
|           <label for="address1" class="block text-sm font-medium text-gray-700" | ||||
|             >{$_("address")}</label | ||||
|           > | ||||
|           <input | ||||
|             autocomplete="off" | ||||
|             placeholder="Address" | ||||
|             class:border-red-500={address.address1.length == 0} | ||||
|             class:focus:border-red-500={address.address1.length == 0} | ||||
|             class:focus:ring-red-500={address.address1.length == 0} | ||||
|             bind:value={address.address1} | ||||
|             type="text" | ||||
|             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" | ||||
|           /> | ||||
|         </div> | ||||
|         <div class="col-span-6"> | ||||
|           <label for="address2" class="block text-sm font-medium text-gray-700" | ||||
|             >{$_("apartment-suite-etc")}</label | ||||
|           > | ||||
|           <input | ||||
|             autocomplete="off" | ||||
|             placeholder={$_("apartment-suite-etc")} | ||||
|             bind:value={address.address2} | ||||
|             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-neutral-800 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={address.postalcode.length == 0} | ||||
|             class:focus:border-red-500={address.postalcode.length == 0} | ||||
|             class:focus:ring-red-500={address.postalcode.length == 0} | ||||
|             bind:value={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-neutral-800 rounded-md p-2" | ||||
|           /> | ||||
|         </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={address.city.length == 0} | ||||
|             class:focus:border-red-500={address.city.length == 0} | ||||
|             class:focus:ring-red-500={address.city.length == 0} | ||||
|             bind:value={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-neutral-800 rounded-md p-2" | ||||
|           /> | ||||
|   <div> | ||||
|     <div class="w-full max-w-md space-y-4 mb-6"> | ||||
|       {#if last_created} | ||||
|         <div class="mt-4 p-3 bg-green-50 border border-green-200 rounded-md"> | ||||
|           <p class="text-black"> | ||||
|             {$_("last-created-donation")}: #{last_created.id}: {last_created.amountPerDistance / | ||||
|               100} € für {getRunnerLabel(last_created.runner)} von {getRunnerLabel( | ||||
|               last_created.donor | ||||
|             )} | ||||
|           </p> | ||||
|         </div> | ||||
|       {/if} | ||||
|     </div> | ||||
|     <div> | ||||
|       <h4 class="text-xl font-semibold"> | ||||
|         {$_("amount-per-kilometer")} | ||||
|       </h4> | ||||
|       <div class="mt-1 flex rounded-md shadow-sm"> | ||||
|         <input | ||||
|           autocomplete="off" | ||||
|           class:border-red-500={!amount > 0} | ||||
|           class:focus:border-red-500={!amount > 0} | ||||
|           class:focus:ring-red-500={!amount > 0} | ||||
|           bind:value={amount} | ||||
|           type="number" | ||||
|           step="0.01" | ||||
|           name="donation_amount_eur" | ||||
|           class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 p-2" | ||||
|           placeholder="2.00" | ||||
|  | ||||
|       <!-- Runner Selection --> | ||||
|       <div> | ||||
|         <h4 class="text-xl font-semibold">{$_("runner")}</h4> | ||||
|         <Select | ||||
|           containerClasses="rounded-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||
|           itemFilter={(label, filterText, option) => | ||||
|             filterRunners(label, filterText, option)} | ||||
|           items={runners} | ||||
|           showChevron={true} | ||||
|           placeholder={$_("search-for-runner-by-name-or-id")} | ||||
|           noOptionsMessage={$_("no-runners-found")} | ||||
|           on:select={(selectedValue) => { | ||||
|             runnerinfo = selectedValue.detail.value; | ||||
|           }} | ||||
|           on:clear={() => (runnerinfo = { id: 0, firstname: "", lastname: "" })} | ||||
|         /> | ||||
|         <span | ||||
|           class="inline-flex items-center px-3 rounded-r-md border border-neutral-300 bg-neutral-50 text-neutral-500 text-sm" | ||||
|           >€</span | ||||
|         > | ||||
|       </div> | ||||
|     </div> | ||||
|     <div> | ||||
|       <h4 class="text-xl font-semibold"> | ||||
|         {$_("confirm")} | ||||
|       </h4> | ||||
|       <button | ||||
|         disabled={amount <= 0 || | ||||
|           runnerinfo.id == 0 || | ||||
|           (donorinfo.firstname.length == 0 || donorinfo.lastname.length == 0)} | ||||
|         class="py-2 px-4 text-center inline-flex items-center text-md 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" | ||||
|         on:click={async () => { | ||||
|           toast.loading($_("creating-donation")); | ||||
|           if (donorinfo.id == 0) { | ||||
|             if (!address_checked) { | ||||
|               address = null | ||||
|  | ||||
|       <!-- Amount Input --> | ||||
|       <div> | ||||
|         <h4 class="text-xl font-semibold">{$_("amount-per-kilometer")}</h4> | ||||
|         <div class="mt-1 flex rounded-md shadow-sm"> | ||||
|           <input | ||||
|             autocomplete="off" | ||||
|             class:border-red-500={!amount > 0} | ||||
|             class:focus:border-red-500={!amount > 0} | ||||
|             class:focus:ring-red-500={!amount > 0} | ||||
|             bind:value={amount} | ||||
|             type="number" | ||||
|             step="0.01" | ||||
|             name="donation_amount_eur" | ||||
|             class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 p-2" | ||||
|             placeholder="2.00" | ||||
|           /> | ||||
|           <span | ||||
|             class="inline-flex items-center px-3 rounded-r-md border border-neutral-300 bg-neutral-50 text-neutral-500 text-sm" | ||||
|             >€</span | ||||
|           > | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|       <!-- Donor Selection --> | ||||
|       <div> | ||||
|         <h4 class="text-xl font-semibold">{$_("donor")}</h4> | ||||
|  | ||||
|         <!-- Donor Type Toggle --> | ||||
|         <div class="mb-2"> | ||||
|           <div class="flex border rounded-md overflow-hidden shadow-sm"> | ||||
|             <button | ||||
|               class:bg-indigo-600={!donor_create_new} | ||||
|               class:text-white={!donor_create_new} | ||||
|               class="py-2 px-4 w-1/2 transition-colors" | ||||
|               on:click={() => { | ||||
|                 donor_create_new = false; | ||||
|                 donorinfo = { id: 0, firstname: "", lastname: "" }; | ||||
|               }} | ||||
|             > | ||||
|               {$_("existing-donor")} | ||||
|             </button> | ||||
|             <button | ||||
|               class={`py-2 px-4 w-1/2 transition-colors ${donor_create_new ? "bg-indigo-600 text-white" : "bg-gray-100 text-gray-700"}`} | ||||
|               on:click={() => { | ||||
|                 donor_create_new = true; | ||||
|                 donorinfo = { id: 0, firstname: "", lastname: "" }; | ||||
|               }} | ||||
|             > | ||||
|               {$_("new-donor")} | ||||
|             </button> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         {#if !donor_create_new} | ||||
|           <Select | ||||
|             containerClasses="rounded-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" | ||||
|             itemFilter={(label, filterText, option) => | ||||
|               filterRunners(label, filterText, option)} | ||||
|             items={donors} | ||||
|             showChevron={true} | ||||
|             placeholder={$_("search-for-donor")} | ||||
|             noOptionsMessage={$_("no-donors-found")} | ||||
|             on:select={(selectedValue) => { | ||||
|               donorinfo = selectedValue.detail.value; | ||||
|             }} | ||||
|             on:clear={() => | ||||
|               (donorinfo = { id: 0, firstname: "", lastname: "" })} | ||||
|           /> | ||||
|         {:else} | ||||
|           <div class="space-y-3"> | ||||
|             <!-- First Name --> | ||||
|             <div> | ||||
|               <label | ||||
|                 for="firstname" | ||||
|                 class="block text-sm font-medium text-gray-700" | ||||
|               > | ||||
|                 {$_("first-name")} | ||||
|               </label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="firstname" | ||||
|                 bind:value={donorinfo.firstname} | ||||
|                 class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 p-2" | ||||
|                 placeholder={$_("first-name")} | ||||
|               /> | ||||
|             </div> | ||||
|  | ||||
|             <!-- Last Name --> | ||||
|             <div> | ||||
|               <label | ||||
|                 for="lastname" | ||||
|                 class="block text-sm font-medium text-gray-700" | ||||
|               > | ||||
|                 {$_("last-name")} | ||||
|               </label> | ||||
|               <input | ||||
|                 type="text" | ||||
|                 id="lastname" | ||||
|                 bind:value={donorinfo.lastname} | ||||
|                 class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 p-2" | ||||
|                 placeholder={$_("last-name")} | ||||
|               /> | ||||
|             </div> | ||||
|  | ||||
|             <!-- Address Checkbox --> | ||||
|             <div class="flex items-start mt-4"> | ||||
|               <div class="flex items-center h-5"> | ||||
|                 <input | ||||
|                   id="address_check" | ||||
|                   type="checkbox" | ||||
|                   bind:checked={address_checked} | ||||
|                   class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" | ||||
|                 /> | ||||
|               </div> | ||||
|               <div class="ml-3 text-sm"> | ||||
|                 <label for="address_check" class="font-medium text-gray-700"> | ||||
|                   {$_("receipt-needed")} | ||||
|                 </label> | ||||
|               </div> | ||||
|             </div> | ||||
|  | ||||
|             {#if address_checked} | ||||
|               <!-- Address Fields --> | ||||
|               <div | ||||
|                 class="space-y-3 mt-3 p-3 border border-gray-200 rounded-md bg-gray-50" | ||||
|               > | ||||
|                 <div> | ||||
|                   <label | ||||
|                     for="address1" | ||||
|                     class="block text-sm font-medium text-gray-700" | ||||
|                   > | ||||
|                     {$_("address")} | ||||
|                   </label> | ||||
|                   <input | ||||
|                     type="text" | ||||
|                     id="address1" | ||||
|                     bind:value={address.address1} | ||||
|                     class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 p-2" | ||||
|                   /> | ||||
|                 </div> | ||||
|  | ||||
|                 <div> | ||||
|                   <label | ||||
|                     for="address2" | ||||
|                     class="block text-sm font-medium text-gray-700" | ||||
|                   > | ||||
|                     {$_("apartment-suite-etc")} | ||||
|                   </label> | ||||
|                   <input | ||||
|                     type="text" | ||||
|                     id="address2" | ||||
|                     bind:value={address.address2} | ||||
|                     class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 p-2" | ||||
|                   /> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="grid grid-cols-2 gap-3"> | ||||
|                   <div> | ||||
|                     <label | ||||
|                       for="postalcode" | ||||
|                       class="block text-sm font-medium text-gray-700" | ||||
|                     > | ||||
|                       {$_("zip-postal-code")} | ||||
|                     </label> | ||||
|                     <input | ||||
|                       type="text" | ||||
|                       id="postalcode" | ||||
|                       bind:value={address.postalcode} | ||||
|                       class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 p-2" | ||||
|                     /> | ||||
|                   </div> | ||||
|  | ||||
|                   <div> | ||||
|                     <label | ||||
|                       for="city" | ||||
|                       class="block text-sm font-medium text-gray-700" | ||||
|                     > | ||||
|                       {$_("city")} | ||||
|                     </label> | ||||
|                     <input | ||||
|                       type="text" | ||||
|                       id="city" | ||||
|                       bind:value={address.city} | ||||
|                       class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 p-2" | ||||
|                     /> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </div> | ||||
|             {/if} | ||||
|           </div> | ||||
|         {/if} | ||||
|       </div> | ||||
|       <!-- Submit Button --> | ||||
|       <div class="mt-6"> | ||||
|         <button | ||||
|           type="button" | ||||
|           class="w-full inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:bg-gray-400 disabled:cursor-not-allowed" | ||||
|           disabled={!amount > 0 || | ||||
|             !runnerinfo.id || | ||||
|             (!donorinfo.id && !donor_create_new) || | ||||
|             (donor_create_new && | ||||
|               (!donorinfo.firstname || !donorinfo.lastname)) || | ||||
|             (donor_create_new && | ||||
|               address_checked && | ||||
|               (!address.address1 || !address.city || !address.postalcode))} | ||||
|           on:click={async () => { | ||||
|             if (donor_create_new) { | ||||
|               donorinfo = await DonorService.donorControllerPost({ | ||||
|                 firstname: donorinfo.firstname, | ||||
|                 lastname: donorinfo.lastname, | ||||
|                 receiptNeeded: address_checked, | ||||
|                 ...(address_checked ? { address: address } : {}), | ||||
|               }); | ||||
|             } | ||||
|             donorinfo = await DonorService.donorControllerPost({ | ||||
|               firstname: donorinfo.firstname, | ||||
|               lastname: lastname, | ||||
|               receiptNeeded: address_checked, | ||||
|               address: address, | ||||
|             }); | ||||
|             loadDonors(); | ||||
|           } | ||||
|           await DonationService.donationControllerPostDistance({ | ||||
|             amountPerDistance: amount*100, | ||||
|             runner: runnerinfo.id, | ||||
|             donor: donorinfo.id, | ||||
|           }); | ||||
|           toast.dismiss(); | ||||
|           toast.success($_("donation-created")); | ||||
|           resetAll(); | ||||
|         }}>{$_("create")}</button | ||||
|       > | ||||
|       {amount <= 0 || | ||||
|           runnerinfo.id == 0 || | ||||
|           (donorinfo.firstname.length == 0 && donorinfo.lastname.length == 0)} | ||||
|           {amount} - {runnerinfo.id} - {donorinfo.id} - {donorinfo.firstname} - {donorinfo.lastname} | ||||
|  | ||||
|             DonationService.donationControllerPostDistance({ | ||||
|               donor: donorinfo.id, | ||||
|               runner: runnerinfo.id, | ||||
|               amountPerDistance: amount * 100, | ||||
|             }) | ||||
|               .then((data) => { | ||||
|                 last_created = data; | ||||
|                 toast.success($_("donation-created-successfully")); | ||||
|                 resetAll(); | ||||
|                 loadDonors(); | ||||
|               }) | ||||
|               .catch((err) => { | ||||
|                 console.error("Error creating donation:", err); | ||||
|                 toast.error($_("error-creating-donation")); | ||||
|               }); | ||||
|           }} | ||||
|         > | ||||
|           {$_("create")} | ||||
|         </button> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
|   | ||||
| @@ -199,6 +199,7 @@ | ||||
|     "donation-amount": "Sponsoringbetrag", | ||||
|     "donation-amount-must-be-greater-that-0-00eur": "Der Sponsoringbetrag muss größer als 0.00€ sein.", | ||||
|     "donation-created": "Sponsoring erstellt", | ||||
|     "donation-created-successfully": "Sponsoring erstellt", | ||||
|     "donation-deleted": "Sponsoring gelöscht", | ||||
|     "donation-quick-add": "Sponsoringschnelleingabe", | ||||
|     "donation-updated": "Sponsoring wurde aktualisiert", | ||||
| @@ -226,10 +227,12 @@ | ||||
|     "enabled_large": "Aktiviert", | ||||
|     "english": "Englisch", | ||||
|     "enter-payment": "Zahlung eingeben", | ||||
|     "error-creating-donation": "Fehler bei der Anlage", | ||||
|     "error-during-import": "Fehler beim Importieren", | ||||
|     "error-whyile-copying-to-clipboard": "Fehler beim Kopieren in die Zwischenablage", | ||||
|     "error_on_login": "😢Fehler beim Login", | ||||
|     "everything-concerning-your-profile": "Alles zu deinem Profil", | ||||
|     "existing-donor": "Existierende Sponsor:in", | ||||
|     "faq": "FAQ", | ||||
|     "fast_card_replacement": "Karten-Schnellzusweisung (Mit Mobilgeräteunterstützung)", | ||||
|     "fast_donation_create": "Sponsoring-Schnellanlage", | ||||
| @@ -279,6 +282,7 @@ | ||||
|     "key": "Schlüssel", | ||||
|     "laeufer-hinzufuegen": "Läufer hinzufügen", | ||||
|     "laptime": "Rundenzeit", | ||||
|     "last-created-donation": "Zuletzt erstellt", | ||||
|     "last-name": "Nachname", | ||||
|     "last-name-is-required": "Nachname muss angegeben werden", | ||||
|     "lfk-is-os": "Das \"Lauf für Kaya!\" Frontend ist (wie alle anderen Projekte für den \"LfK!\" auch) ein OpenSource Projekt.", | ||||
| @@ -311,6 +315,7 @@ | ||||
|     "must-contain-a-uppercase-letter": "Passwort muss einen Kleinbuchstaben enthalten!", | ||||
|     "name": "Name", | ||||
|     "name-is-required": "Der Gruppenname muss angegeben werden", | ||||
|     "new-donor": "Neue Sponsor:in", | ||||
|     "new-password": "Neues Passwort", | ||||
|     "next_runner": "Nächster Läufer", | ||||
|     "no-address": "Keine Adresse hinterlegt", | ||||
| @@ -420,6 +425,7 @@ | ||||
|     "scanstations-are-being-loaded": "Scannerstationen werden geladen...", | ||||
|     "search-for-an-organization-by-name-or-id": "Suche eine Organisation (via Name oder #ID)", | ||||
|     "search-for-an-organization-or-team-by-name-or-id": "Suche eine Organisation oder ein Team (via Name oder #ID)", | ||||
|     "search-for-donor": "Nach Sponsor:in suchen", | ||||
|     "search-for-donor-name-or-id": "Suche eine Sponsor (via Name oder #ID)", | ||||
|     "search-for-permission": "Berechtigungen durchsuchen", | ||||
|     "search-for-runner-by-name-or-id": "Suche einen Läufer (via Name oder #ID)", | ||||
|   | ||||
| @@ -199,6 +199,7 @@ | ||||
|     "donation-amount": "Donation amount", | ||||
|     "donation-amount-must-be-greater-that-0-00eur": "Donation amount must be greater that 0.00€", | ||||
|     "donation-created": "Created sponsoring", | ||||
|     "donation-created-successfully": "Donation created", | ||||
|     "donation-deleted": "Donation deleted", | ||||
|     "donation-quick-add": "Mass sponsoring creation", | ||||
|     "donation-updated": "Donation updated", | ||||
| @@ -230,6 +231,7 @@ | ||||
|     "error-whyile-copying-to-clipboard": "Error while copying to clipboard", | ||||
|     "error_on_login": "Error on login", | ||||
|     "everything-concerning-your-profile": "Everything concerning your profile", | ||||
|     "existing-donor": "Existing Donor", | ||||
|     "faq": "FAQ", | ||||
|     "fast_card_replacement": "Fast card replacement (with mobile support)", | ||||
|     "fast_donation_create": "Mass donation creator", | ||||
| @@ -279,6 +281,7 @@ | ||||
|     "key": "Key", | ||||
|     "laeufer-hinzufuegen": "Add runner", | ||||
|     "laptime": "Laptime", | ||||
|     "last-created-donation": "Last created", | ||||
|     "last-name": "Last name", | ||||
|     "last-name-is-required": "Last Name is required", | ||||
|     "lfk-is-os": "The \"Lauf für Kaya!\" Frontend is (like all other projects for the \"LfK!\" Also) an open source project.", | ||||
| @@ -310,6 +313,7 @@ | ||||
|     "must-contain-a-uppercase-letter": "Must contain a uppercase letter!", | ||||
|     "name": "Name", | ||||
|     "name-is-required": "Name is required", | ||||
|     "new-donor": "New donor", | ||||
|     "new-password": "New password", | ||||
|     "next_runner": "Next Runner", | ||||
|     "no-address": "no address", | ||||
| @@ -419,6 +423,7 @@ | ||||
|     "scanstations-are-being-loaded": "Loading scanstations...", | ||||
|     "search-for-an-organization-by-name-or-id": "Search for an organization (by name or #ID)", | ||||
|     "search-for-an-organization-or-team-by-name-or-id": "Search for an organization or team (by name or #ID)", | ||||
|     "search-for-donor": "Search for donor", | ||||
|     "search-for-donor-name-or-id": "Search for donor (by name or #ID)", | ||||
|     "search-for-permission": "Search for permission", | ||||
|     "search-for-runner-by-name-or-id": "Search for runner (by name or #ID)", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user