refactor(donation): Refactor donor selection and add new donor creation functionality
This commit is contained in:
		| @@ -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,221 +68,280 @@ | ||||
|     runnerinfo = { id: 0, firstname: "", lastname: "" }; | ||||
|     donorinfo = { id: 0, firstname: "", lastname: "" }; | ||||
|     amount = 0; | ||||
|     address_checked = false; | ||||
|     donor_create_new = false; | ||||
|   } | ||||
| </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 | ||||
|       > | ||||
|  | ||||
|             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> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user