All checks were successful
		
		
	
	Build Latest and dev images / build-container (push) Successful in 1m0s
				
			
		
			
				
	
	
		
			353 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
			
		
		
	
	
			353 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
| <script>
 | |
| 	import { _ } from "svelte-i18n";
 | |
| 	import store from "../../store";
 | |
| 	import {
 | |
| 		DonationService,
 | |
| 		DonorService,
 | |
| 		RunnerService,
 | |
| 	} from "@odit/lfk-client-js";
 | |
| 	import toast from "svelte-french-toast";
 | |
| 
 | |
| 	import PromiseError from "../base/PromiseError.svelte";
 | |
| 	import Select from "svelte-select";
 | |
| 	let data_loaded = false;
 | |
| 	export let params;
 | |
| 	$: delete_triggered = false;
 | |
| 	$: original_data = {};
 | |
| 	$: editable = {};
 | |
| 	$: donor = {};
 | |
| 	$: runner = {};
 | |
| 	$: current_donors = [];
 | |
| 	$: current_runners = [];
 | |
| 	$: amount_input = 0;
 | |
| 	$: is_amount_valid = amount_input > 0;
 | |
| 	$: paid_amount_input = 0;
 | |
| 	$: is_paid_amount_valid = paid_amount_input > 0;
 | |
| 	$: is_everything_set =
 | |
| 		editable.donor != null &&
 | |
| 		((original_data.responseType == "DISTANCEDONATION" &&
 | |
| 			editable?.runner != null) ||
 | |
| 			original_data.responseType !== "DISTANCEDONATION");
 | |
| 	$: changes_performed =
 | |
| 		!(JSON.stringify(original_data) === JSON.stringify(editable)) ||
 | |
| 		(original_data.responseType == "DISTANCEDONATION" &&
 | |
| 			!(Math.floor(amount_input * 100) === original_data.amountPerDistance)) ||
 | |
| 		(original_data.responseType !== "DISTANCEDONATION" &&
 | |
| 			!(Math.floor(amount_input * 100) === original_data.amount)) ||
 | |
| 		!(Math.floor(paid_amount_input * 100) === original_data.paidAmount);
 | |
| 	$: save_enabled = changes_performed && is_amount_valid && is_everything_set;
 | |
| 
 | |
| 	const promise = DonationService.donationControllerGetOne(
 | |
| 		params.donationid
 | |
| 	).then((data) => {
 | |
| 		data_loaded = true;
 | |
| 		original_data = Object.assign({}, data);
 | |
| 		editable = Object.assign({}, original_data);
 | |
| 		paid_amount_input = data.paidAmount / 100;
 | |
| 		if (data.responseType == "DISTANCEDONATION") {
 | |
| 			amount_input = data.amountPerDistance / 100;
 | |
| 			RunnerService.runnerControllerGetAll().then((val) => {
 | |
| 				current_runners = val.map((r) => {
 | |
| 					return { label: getDonorLabel(r), value: r };
 | |
| 				});
 | |
| 				runner = current_runners.find((g) => g.value.id == editable.runner.id);
 | |
| 			});
 | |
| 		} else {
 | |
| 			amount_input = data.amount / 100;
 | |
| 		}
 | |
| 		DonorService.donorControllerGetAll().then((val) => {
 | |
| 			current_donors = val.map((r) => {
 | |
| 				return { label: getDonorLabel(r), value: r };
 | |
| 			});
 | |
| 			donor = current_donors.find((g) => g.value.id == editable.donor.id);
 | |
| 		});
 | |
| 	});
 | |
| 	const getDonorLabel = (option) =>
 | |
| 		option.firstname + " " + (option.middlename || "") + " " + option.lastname;
 | |
| 	const filterDonors = (label, filterText, option) =>
 | |
| 		label.toLowerCase().includes(filterText.toLowerCase()) ||
 | |
| 		option.value.id.toString().startsWith(filterText.toLowerCase());
 | |
| 
 | |
| 	function submit() {
 | |
| 		if (data_loaded === true && save_enabled) {
 | |
| 			toast($_("updating-donation"));
 | |
| 			let postdata = {};
 | |
| 			editable.paidAmount = paid_amount_input * 100;
 | |
| 			if (original_data.responseType === "DISTANCEDONATION") {
 | |
| 				editable.amountPerDistance = Math.floor(amount_input * 100);
 | |
| 				postdata = Object.assign(postdata, editable);
 | |
| 				postdata.runner = postdata.runner.id;
 | |
| 				postdata.donor = postdata.donor.id;
 | |
| 				DonationService.donationControllerPutDistance(
 | |
| 					original_data.id,
 | |
| 					postdata
 | |
| 				)
 | |
| 					.then((resp) => {
 | |
| 						Object.assign(original_data, editable);
 | |
| 						original_data = original_data;
 | |
| 						toast.success($_("donation-updated"));
 | |
| 					})
 | |
| 					.catch((err) => {});
 | |
| 			} else {
 | |
| 				editable.amount = Math.floor(amount_input * 100);
 | |
| 				postdata = Object.assign(postdata, editable);
 | |
| 				postdata.donor = postdata.donor.id;
 | |
| 				DonationService.donationControllerPutFixed(original_data.id, postdata)
 | |
| 					.then((resp) => {
 | |
| 						Object.assign(original_data, editable);
 | |
| 						original_data = original_data;
 | |
| 						toast.success($_("donation-updated"));
 | |
| 					})
 | |
| 					.catch((err) => {});
 | |
| 			}
 | |
| 		} else {
 | |
| 		}
 | |
| 	}
 | |
| 	function deleteDonation() {
 | |
| 		DonationService.donationControllerRemove(original_data.id, false)
 | |
| 			.then((resp) => {
 | |
| 				toast.success($_("donation-deleted"));
 | |
| 				location.replace("./");
 | |
| 			})
 | |
| 			.catch((err) => {
 | |
| 				modal_open = true;
 | |
| 				delete_donor = original_data;
 | |
| 			});
 | |
| 	}
 | |
| </script>
 | |
| 
 | |
| {#await promise}
 | |
| 	{$_("loading-donation-details")}
 | |
| {:then}
 | |
| 	<section class="container p-5 select-none">
 | |
| 		<div class="flex flex-row mb-4">
 | |
| 			<div class="mt-2 w-full">
 | |
| 				<nav class="w-full flex">
 | |
| 					<ol class="list-none flex flex-row items-center justify-start">
 | |
| 						<li class="flex items-center">
 | |
| 							<a class="mr-2" href="./"
 | |
| 								><svg
 | |
| 									xmlns="http://www.w3.org/2000/svg"
 | |
| 									width="24"
 | |
| 									height="24"
 | |
| 									viewBox="0 0 24 24"
 | |
| 									fill="none"
 | |
| 									stroke="currentColor"
 | |
| 									stroke-width="2"
 | |
| 									stroke-linecap="round"
 | |
| 									stroke-linejoin="round"
 | |
| 									class="inline-block"
 | |
| 									><path d="m12 19-7-7 7-7" /><path d="M19 12H5" /></svg
 | |
| 								>
 | |
| 								{$_("donations")}</a
 | |
| 							>
 | |
| 						</li>
 | |
| 					</ol>
 | |
| 				</nav>
 | |
| 			</div>
 | |
| 		</div>
 | |
| 		<div class="mb-4 text-3xl font-extrabold leading-tight">
 | |
| 			{original_data.donor.firstname}
 | |
| 			{original_data.donor.middlename || ""}
 | |
| 			{original_data.donor.lastname}
 | |
| 			>
 | |
| 			{#if original_data.responseType == "DISTANCEDONATION"}
 | |
| 				{original_data.runner.firstname}
 | |
| 				{original_data.runner.middlename || ""}
 | |
| 				{original_data.runner.lastname}
 | |
| 			{:else}
 | |
| 				{$_("fixed-donation")}:
 | |
| 				{amount_input.toFixed(2).toLocaleString("de-DE", { valute: "EUR" })}€
 | |
| 			{/if}
 | |
| 			[#{original_data.id}]
 | |
| 			<div data-id="donation_actions_${original_data.id}">
 | |
| 				{#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:DELETE")}
 | |
| 					{#if delete_triggered}
 | |
| 						<button
 | |
| 							on:click={deleteDonation}
 | |
| 							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"
 | |
| 							>{$_("confirm-deletion")}</button
 | |
| 						>
 | |
| 						<button
 | |
| 							on:click={() => {
 | |
| 								delete_triggered = !delete_triggered;
 | |
| 							}}
 | |
| 							class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm"
 | |
| 							>{$_("cancel")}</button
 | |
| 						>
 | |
| 					{/if}
 | |
| 					{#if !delete_triggered}
 | |
| 						<button
 | |
| 							on:click={() => {
 | |
| 								delete_triggered = true;
 | |
| 							}}
 | |
| 							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"
 | |
| 							>{$_("delete-donation")}</button
 | |
| 						>
 | |
| 					{/if}
 | |
| 				{/if}
 | |
| 				{#if !delete_triggered}
 | |
| 					<button
 | |
| 						disabled={!save_enabled}
 | |
| 						class:opacity-50={!save_enabled}
 | |
| 						type="button"
 | |
| 						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"
 | |
| 						>{$_("save-changes")}</button
 | |
| 					>
 | |
| 				{/if}
 | |
| 			</div>
 | |
| 		</div>
 | |
| 		<!--  -->
 | |
| 		<div>
 | |
| 			<span class="font-semibold text-gray-700"
 | |
| 				>{$_("total-donation-amount")}:</span
 | |
| 			>
 | |
| 			<span
 | |
| 				>{(editable.amount / 100)
 | |
| 					.toFixed(2)
 | |
| 					.toLocaleString("de-DE", { valute: "EUR" })}€</span
 | |
| 			>
 | |
| 			|
 | |
| 			<span class="font-semibold text-gray-700">{$_("paid-amount")}:</span>
 | |
| 			<span
 | |
| 				>{(editable.paidAmount / 100)
 | |
| 					.toFixed(2)
 | |
| 					.toLocaleString("de-DE", { valute: "EUR" })}€</span
 | |
| 			>
 | |
| 			|
 | |
| 			<span class="font-semibold text-gray-700">{$_("status")}:</span>
 | |
| 			{#if editable.status == "PAID"}
 | |
| 				<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
 | |
| 				>
 | |
| 			{:else}
 | |
| 				<span
 | |
| 					class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full border border-current bg-red-100 text-red-800"
 | |
| 					>{$_("open")}</span
 | |
| 				>
 | |
| 			{/if}
 | |
| 		</div>
 | |
| 		<br />
 | |
| 		<div class=" mt-2 w-full">
 | |
| 			<label for="donor" class="block font-semibold text-gray-700"
 | |
| 				>{$_("donor")}</label
 | |
| 			>
 | |
| 			<Select
 | |
| 				containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
 | |
| 				itemFilter={(label, filterText, option) =>
 | |
| 					filterDonors(label, filterText, option)}
 | |
| 				items={current_donors}
 | |
| 				showChevron={true}
 | |
| 				placeholder={$_("search-for-donor-name-or-id")}
 | |
| 				noOptionsMessage={$_("no-donors-found")}
 | |
| 				bind:selectedValue={donor}
 | |
| 				on:select={(selectedValue) => {
 | |
| 					editable.donor = selectedValue.detail.value;
 | |
| 					editable.donor.donationAmount = original_data.donor.donationAmount;
 | |
| 					editable.donor.paidDonationAmount =
 | |
| 						original_data.donor.paidDonationAmount;
 | |
| 				}}
 | |
| 				on:clear={() => (editable.donor = null)}
 | |
| 			/>
 | |
| 		</div>
 | |
| 		{#if original_data.responseType == "DISTANCEDONATION"}
 | |
| 			<div class=" mt-2 w-full">
 | |
| 				<label for="donor" class="block font-semibold text-gray-700"
 | |
| 					>{$_("runner")}</label
 | |
| 				>
 | |
| 				<Select
 | |
| 					containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
 | |
| 					itemFilter={(label, filterText, option) =>
 | |
| 						filterDonors(label, filterText, option)}
 | |
| 					items={current_runners}
 | |
| 					showChevron={true}
 | |
| 					placeholder={$_("search-for-runner-by-name-or-id")}
 | |
| 					noOptionsMessage={$_("no-runners-found")}
 | |
| 					bind:selectedValue={runner}
 | |
| 					on:select={(selectedValue) =>
 | |
| 						(editable.runner = selectedValue.detail.value)}
 | |
| 					on:clear={() => (editable.runner = null)}
 | |
| 				/>
 | |
| 			</div>
 | |
| 		{/if}
 | |
| 		<div class=" mt-2 w-full">
 | |
| 			<label for="lastname" class="font-semibold text-gray-700">
 | |
| 				{#if original_data.responseType == "DISTANCEDONATION"}
 | |
| 					{$_("amount-per-kilometer")}
 | |
| 				{:else}{$_("donation-amount")}{/if}
 | |
| 			</label>
 | |
| 			<div class="mt-1 flex rounded-md shadow-sm">
 | |
| 				<input
 | |
| 					autocomplete="off"
 | |
| 					class:border-red-500={!is_amount_valid}
 | |
| 					class:focus:border-red-500={!is_amount_valid}
 | |
| 					class:focus:ring-red-500={!is_amount_valid}
 | |
| 					bind:value={amount_input}
 | |
| 					type="number"
 | |
| 					step="0.01"
 | |
| 					name="donation_amount_eur"
 | |
| 					class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm: border-gray-300 border bg-gray-50 text-neutral-800 p-2"
 | |
| 					placeholder="2.00"
 | |
| 				/>
 | |
| 				<span
 | |
| 					class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500"
 | |
| 					>€</span
 | |
| 				>
 | |
| 			</div>
 | |
| 			{#if !is_amount_valid}
 | |
| 				<span
 | |
| 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
 | |
| 				>
 | |
| 					{$_("donation-amount-must-be-greater-that-0-00eur")}
 | |
| 				</span>
 | |
| 			{/if}
 | |
| 		</div>
 | |
| 		<div class="mt-2 w-full">
 | |
| 			<label for="token" class="block font-semibold text-gray-700"
 | |
| 				>{$_("paid-amount")}</label
 | |
| 			>
 | |
| 			<div
 | |
| 				class="inline-flex border-gray-300 border rounded-l-md rounded-r-md bg-gray-50 text-gray-500 w-full"
 | |
| 			>
 | |
| 				<input
 | |
| 					autocomplete="off"
 | |
| 					class:border-red-500={!is_amount_valid}
 | |
| 					class:focus:border-red-500={!is_amount_valid}
 | |
| 					class:focus:ring-red-500={!is_amount_valid}
 | |
| 					bind:value={paid_amount_input}
 | |
| 					type="number"
 | |
| 					step="0.01"
 | |
| 					name="donation_amount_eur"
 | |
| 					class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm p-2"
 | |
| 					placeholder="2.00"
 | |
| 				/>
 | |
| 				<button
 | |
| 					on:click={() => {
 | |
| 						paid_amount_input = paid_amount_input = (
 | |
| 							original_data.amount / 100
 | |
| 						).toFixed(2);
 | |
| 					}}
 | |
| 					class="inline-flex items-center p-r-2 text-indigo-300 hover:text-indigo-700 text-sm"
 | |
| 					>MAX</button
 | |
| 				>
 | |
| 				<span
 | |
| 					class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm"
 | |
| 					>€</span
 | |
| 				>
 | |
| 			</div>
 | |
| 			{#if !is_paid_amount_valid}
 | |
| 				<span
 | |
| 					class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
 | |
| 				>
 | |
| 					{$_("payment-amount-must-be-greater-than-0-00eur")}
 | |
| 				</span>
 | |
| 			{/if}
 | |
| 		</div>
 | |
| 	</section>
 | |
| {:catch error}
 | |
| 	<PromiseError {error} />
 | |
| {/await}
 |