Merge pull request 'Donation management feature/79-donation_management' (#87) from feature/79-donation_management into dev
All checks were successful
continuous-integration/drone/push Build is passing

Reviewed-on: #87
This commit is contained in:
Nicolai Ort 2021-02-25 16:35:10 +00:00
commit 03be2d0492
13 changed files with 977 additions and 63 deletions

View File

@ -0,0 +1,7 @@
languageIds:
- javascript
- svelte
- html
monopoly: false
refactorTemplates:
- "{$_('$1')}"

View File

@ -64,6 +64,8 @@
import ContactDetail from "./components/contacts/ContactDetail.svelte"; import ContactDetail from "./components/contacts/ContactDetail.svelte";
import Donors from "./components/donors/Donors.svelte"; import Donors from "./components/donors/Donors.svelte";
import DonorDetail from "./components/donors/DonorDetail.svelte"; import DonorDetail from "./components/donors/DonorDetail.svelte";
import Donations from "./components/donations/Donations.svelte";
import DonationDetail from "./components/donations/DonationDetail.svelte";
store.init(); store.init();
registerSW(); registerSW();
</script> </script>
@ -154,6 +156,14 @@
<DonorDetail {params} /> <DonorDetail {params} />
</Route> </Route>
</Route> </Route>
<Route path="/donations/*">
<Route path="/">
<Donations />
</Route>
<Route path="/:donationid" let:params>
<DonationDetail {params} />
</Route>
</Route>
<Route path="/about"> <Route path="/about">
<About /> <About />
</Route> </Route>

View File

@ -121,6 +121,23 @@
<span>{$_('donors')}</span> <span>{$_('donors')}</span>
</a> </a>
{/if} {/if}
{#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:GET')}
<a
class:bg-gray-100={$router.path.includes('/donations/')}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="/donations/">
<svg
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"
viewBox="0 0 24 24"
width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z" /></svg>
<span>{$_('donations')}</span>
</a>
{/if}
{#if store.state.jwtinfo.userdetails.permissions.includes('TRACK:GET')} {#if store.state.jwtinfo.userdetails.permissions.includes('TRACK:GET')}
<a <a
class:bg-gray-100={$router.path === '/tracks/'} class:bg-gray-100={$router.path === '/tracks/'}

View File

@ -0,0 +1,288 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import {
DonationService,
DonorService,
RunnerService,
} from "@odit/lfk-client-js";
import Toastify from "toastify-js";
export let modal_open;
export let current_donations;
function focus(el) {
el.focus();
}
$: donor = 0;
$: runner = 0;
$: donors = [];
$: runners = [];
$: is_fixed = false;
DonorService.donorControllerGetAll().then((val) => {
donors = val;
donor = donors[0].id || 0;
});
RunnerService.runnerControllerGetAll().then((val) => {
runners = val;
runner = runners[0].id || 0;
});
$: amount_input = 0;
$: processed_last_submit = true;
$: is_amount_valid = amount_input > 0;
$: createbtnenabled = is_amount_valid;
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
})();
function submit() {
if (processed_last_submit === true) {
let amount_cent = Math.floor(amount_input * 100);
processed_last_submit = false;
const toast = Toastify({
text: "adding donation",
duration: -1,
}).showToast();
if (is_fixed) {
let postdata = {
donor,
amount: amount_cent,
};
DonationService.donationControllerPostFixed(postdata)
.then((result) => {
donor = donors[0].id || 0;
runner = runners[0].id || 0;
amount_input = 0;
modal_open = false;
//
Toastify({
text: "donation_added",
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
current_donations.push(result);
current_donations = current_donations;
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
//
toast.hideToast();
});
} else {
let postdata = {
donor,
runner,
amountPerDistance: amount_cent,
};
DonationService.donationControllerPostDistance(postdata)
.then((result) => {
donor = donors[0].id || 0;
runner = runners[0].id || 0;
amount_input = 0;
modal_open = false;
//
Toastify({
text: "donation_added",
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
current_donations.push(result);
current_donations = current_donations;
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
//
toast.hideToast();
});
}
}
}
</script>
<style>
input:before {
content: "";
position: absolute;
width: 1.25rem;
height: 1.25rem;
border-radius: 50%;
top: 0;
left: 0;
transform: scale(1.1);
box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.2);
background-color: white;
transition: 0.2s ease-in-out;
}
input:checked {
/* @apply: bg-indigo-400; */
background-color: #7f9cf5;
}
input:checked:before {
left: 1.25rem;
}
</style>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div
class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop" />
</div>
<span
class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</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"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z" /></svg>
</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">
<!-- TODO: -->
{#if is_fixed}{$_('create-a-new-fixed-donation')}{:else}{$_('create-a-new-distance-donation')}{/if}
</h3>
<label class="content-center align-middle object-center">
<span
class="ml-2 text-base"
class:text-gray-300={is_fixed}>{$_('distance-donation')}</span>
<input
class="relative w-10 h-5 transition-all duration-200 ease-in-out bg-gray-400 rounded-full shadow-inner outline-none appearance-none align-middle"
type="checkbox"
bind:checked={is_fixed} />
<span
class="ml-2 text-base "
class:text-gray-300={!is_fixed}>{$_('fixed-donation')}</span>
</label>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_('please-provide-the-nessecary-information-to-create-a-new-donation')}
</p>
</div>
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<label
for="donor"
class="block text-sm font-medium text-gray-700">{$_('donor')}</label>
<select
bind:value={donor}
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 donors as d}
<option value={d.id}>
{d.firstname}
{d.middlename || ''}
{d.lastname}
</option>
{/each}
</select>
</div>
{#if !is_fixed}
<div class="col-span-6">
<label
for="donor"
class="block text-sm font-medium text-gray-700">{$_('runner')}</label>
<select
bind:value={runner}
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 runners as r}
<option value={r.id}>
{r.firstname}
{r.middlename || ''}
{r.lastname}
</option>
{/each}
</select>
</div>
{/if}
<div class="col-span-6">
<label
for="donation_amount_eur"
class="block text-sm font-medium text-gray-700">
{#if !is_fixed}{$_('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:text-sm border-gray-300 border bg-gray-50 text-gray-500 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 text-sm">€</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>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
{$_('create')}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
{$_('cancel')}
</button>
</div>
</div>
</div>
</div>
{/if}

View File

@ -0,0 +1,265 @@
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import {
DonationService,
DonorService,
RunnerService,
} from "@odit/lfk-client-js";
import Toastify from "toastify-js";
import PromiseError from "../base/PromiseError.svelte";
let data_loaded = false;
export let params;
$: delete_triggered = false;
$: original_data = {};
$: original_comparison_string = "";
$: editable = {};
$: current_donors = [];
$: current_runners = [];
$: amount_input = 0;
$: is_amount_valid = amount_input > 0;
$: changes_performed =
!(original_comparison_string === 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));
$: save_enabled = changes_performed && is_amount_valid;
const donor_promise = DonorService.donorControllerGetAll().then((val) => {
current_donors = val;
});
const runner_promise = RunnerService.runnerControllerGetAll().then((val) => {
current_runners = val;
});
const promise = DonationService.donationControllerGetOne(
params.donationid
).then((data) => {
data_loaded = true;
original_data = Object.assign(original_data, data);
editable = Object.assign(editable, original_data);
editable.donor = data.donor.id;
if (data.responseType == "DISTANCEDONATION") {
editable.runner = data.runner.id;
amount_input = data.amountPerDistance / 100;
} else {
amount_input = data.amount / 100;
}
original_comparison_string = JSON.stringify(editable);
});
function submit() {
if (data_loaded === true && save_enabled) {
Toastify({
text: "Donation is being updated",
duration: 2500,
}).showToast();
if (original_data.responseType === "DISTANCEDONATION") {
editable.amountPerDistance = Math.floor(amount_input * 100);
DonationService.donationControllerPutDistance(
original_data.id,
editable
)
.then((resp) => {
Object.assign(original_data, resp);
original_data = original_data;
Toastify({
text: "updated donation",
duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
})
.catch((err) => {});
} else {
editable.amount = Math.floor(amount_input * 100);
DonationService.donationControllerPutFixed(original_data.id, editable)
.then((resp) => {
Object.assign(original_data, editable);
original_data = original_data;
Toastify({
text: "updated donation",
duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
})
.catch((err) => {});
}
} else {
}
}
function deleteDonation() {
DonationService.donationControllerRemove(original_data.id, false)
.then((resp) => {
Toastify({
text: "Donation delete",
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
location.replace("./");
})
.catch((err) => {
modal_open = true;
delete_donor = original_data;
});
}
</script>
{#await donor_promise && runner_promise && promise}
{$_('loading-donation-details')}
{:then}
<section class="container p-5 select-none">
<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="flex items-center">
<svg
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" />
<path
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>
</li>
<li class="flex items-center ml-2">
<a class="mr-2" href="./">{$_('donations')}</a><svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="h-3 w-3 mr-2 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"><line
x1="5"
y1="12"
x2="19"
y2="12" />
<polyline points="12 5 19 12 12 19" /></svg>
</li>
<li class="flex items-center">
<span class="mr-2">{original_data.id}</span>
</li>
</ol>
</nav>
</div>
</div>
<div class="mb-8 text-3xl font-extrabold leading-tight">
{original_data.donor.firstname}
{original_data.donor.middlename || ''}
{original_data.donor.lastname}
&gt;
{#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}
<span 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:ml-3 sm:w-auto 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:">{$_('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:ml-3 sm:w-auto 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:ml-3 sm:w-auto sm:">{$_('save-changes')}</button>
{/if}
</span>
</div>
<!-- -->
<div>
<span class="font-medium text-gray-700">{$_('total-donation-amount')}:</span>
<span>{(editable.amount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}€</span>
</div>
<div class=" w-full">
<label
for="donor"
class="block font-medium text-gray-700">{$_('donor')}</label>
<select
bind:value={editable.donor}
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">
{#each current_donors as d}
<option value={d.id}>
{d.firstname}
{d.middlename || ''}
{d.lastname}
</option>
{/each}
</select>
</div>
{#if original_data.responseType == 'DISTANCEDONATION'}
<div class=" w-full">
<label
for="donor"
class="block font-medium text-gray-700">{$_('runner')}</label>
<select
bind:value={editable.runner}
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">
{#each current_runners as r}
<option value={r.id}>
{r.firstname}
{r.middlename || ''}
{r.lastname}
</option>
{/each}
</select>
</div>
{/if}
<div class=" w-full">
<label for="lastname" class="font-medium 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-gray-500 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>
</section>
{:catch error}
<PromiseError {error} />
{/await}

View File

@ -0,0 +1,29 @@
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import AddDonationModal from "./AddDonationModal.svelte";
import DonationsOverview from "./DonationsOverview.svelte";
$: current_donations = [];
export let modal_open = false;
</script>
<section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight">
{$_('donations')}
{#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:CREATE')}
<button
on:click={() => {
modal_open = true;
}}
type="button"
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
{$_('add-donation')}
</button>
{/if}
</span>
<DonationsOverview bind:current_donations />
</section>
{#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:CREATE')}
<AddDonationModal bind:current_donations bind:modal_open />
{/if}

View File

@ -0,0 +1,12 @@
<script>
import { _ } from "svelte-i18n";
import donations_empty from "./donations.svg";
</script>
<div class="text-center items-center justify-center">
<p class="mb-16 text-lg text-gray-500">
<img class="w-full" style="height:15rem" src={donations_empty} alt="" />
<span class="font-bold">There are no donations yet</span><br />
<span>add your fist donation</span>
</p>
</div>

View File

@ -0,0 +1,202 @@
<script>
import { getLocaleFromNavigator, _ } from "svelte-i18n";
import { DonationService, DonorService } from "@odit/lfk-client-js";
import store from "../../store";
import Toastify from "toastify-js";
import DonationsEmptyState from "./DonationsEmptyState.svelte";
$: searchvalue = "";
$: active_deletes = [];
export let current_donations = [];
const donations_promise = DonationService.donationControllerGetAll().then(
(val) => {
current_donations = val;
}
);
function should_display_based_on_id(id) {
if (searchvalue.toString().slice(-1) === "*") {
return id.toString().startsWith(searchvalue.replace("*", ""));
}
return id.toString() === searchvalue;
}
</script>
{#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:GET')}
{#await donations_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">donations are being loaded</p>
<p class="text-sm">{$_('this-might-take-a-moment')}</p>
</div>
{:then}
{#if current_donations.length === 0}
<DonationsEmptyState />
{:else}
<input
type="search"
bind:value={searchvalue}
placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input 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>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('donor')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('runner')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('amount-per-kilometer')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('donation-amount')}
</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_donations as donation}
{#if donation.donor.firstname
.toLowerCase()
.includes(
searchvalue.toLowerCase()
) || donation.donor.middlename
.toLowerCase()
.includes(
searchvalue.toLowerCase()
) || donation.donor.lastname
.toLowerCase()
.includes(
searchvalue.toLowerCase()
) || donation.runner?.firstname
.toLowerCase()
.includes(
searchvalue.toLowerCase()
) || donation.runner?.middlename
.toLowerCase()
.includes(
searchvalue.toLowerCase()
) || donation.runner?.lastname
.toLowerCase()
.includes(
searchvalue.toLowerCase()
) || should_display_based_on_id(donation.id)}
<tr data-rowid="donation_{donation.id}">
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<a
href="../donors/{donation.donor.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{donation.donor.firstname}
{donation.donor.middlename || ''}
{donation.donor.lastname}</a>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
{#if donation.runner}
<div class="text-sm font-medium text-gray-900">
<a
href="../runners/{donation.runner.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{donation.runner.firstname}
{donation.runner.middlename || ''}
{donation.runner.lastname}</a>
</div>
{:else}
<div class="text-sm font-medium text-gray-900">
{$_('fixed-donation')}
</div>
{/if}
</td>
<td class="px-6 py-4 whitespace-nowrap">
{#if donation.amountPerDistance}
<div class="text-sm font-medium text-gray-900">
{(donation.amountPerDistance / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}€
</div>
{:else}
<div class="text-sm font-medium text-gray-900">
{$_('fixed-donation')}
</div>
{/if}
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">
{(donation.amount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}€
</div>
</td>
{#if active_deletes[donation.id] === true}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
on:click={() => {
active_deletes[donation.id] = false;
}}
tabindex="0"
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button>
<button
on:click={() => {
DonationService.donationControllerRemove(donation.id, false).then(
(resp) => {
current_donations = current_donations.filter(
(obj) => obj.id !== donation.id
);
Toastify({
text: 'Donation deleted',
duration: 500,
backgroundColor:
'linear-gradient(to right, #00b09b, #96c93d)',
}).showToast();
}
);
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button>
</td>
{:else}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<a
href="./{donation.id}"
class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a>
{#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:DELETE')}
<button
on:click={() => {
active_deletes[donation.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}

View File

@ -0,0 +1 @@
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="598.11" height="535.11"><path d="M3.35 120.07a4.6 4.6 0 00-3.18 5.66l76.72 273.98a4.6 4.6 0 005.65 3.18l282.82-79.19a4.6 4.6 0 003.18-5.66L291.82 44.07a4.6 4.6 0 00-5.65-3.19z" fill="#e6e6e6"/><path d="M86.1 389.95l269.5-75.46-72.99-260.67-269.5 75.46z" fill="#fff"/><path d="M48.74 164.1c-1.8.5-2.54 3.48-1.65 6.65s3.07 5.33 4.87 4.83l122.91-34.42c1.8-.5 2.54-3.49 1.66-6.65s-3.08-5.34-4.87-4.84zM58.64 199.44c-1.8.5-2.54 3.5-1.65 6.66s3.07 5.34 4.87 4.83l122.91-34.42c1.8-.5 2.54-3.49 1.65-6.65s-3.07-5.34-4.86-4.83zM68.42 234.39c-1.8.5-2.54 3.49-1.65 6.66s3.07 5.33 4.87 4.83l122.92-34.42c1.8-.5 2.54-3.5 1.65-6.66s-3.07-5.33-4.87-4.83zM78.32 269.74c-1.8.5-2.54 3.49-1.65 6.66s3.07 5.33 4.87 4.83l122.92-34.42c1.8-.5 2.54-3.49 1.65-6.66s-3.07-5.33-4.87-4.83zM234.04 112.61a5.97 5.97 0 103.21 11.5l22.98-6.44a5.97 5.97 0 00-3.22-11.49zM243.74 147.28a5.97 5.97 0 103.22 11.49l22.98-6.43a5.97 5.97 0 00-3.22-11.5zM253.45 181.95a5.97 5.97 0 103.22 11.49l22.98-6.44a5.97 5.97 0 00-3.22-11.49zM263.16 216.61a5.97 5.97 0 003.21 11.5l22.98-6.44a5.97 5.97 0 00-3.21-11.49z" fill="#e6e6e6"/><path d="M272.43 276.7a7.6 7.6 0 104.1 14.64l29.28-8.2a7.6 7.6 0 00-4.1-14.64z" fill="#6c63ff"/><path fill="#e6e6e6" d="M85.9 307.81l216.66-60.67.54 1.93-216.67 60.67z"/><path fill="#a0616a" d="M520.2 506.07l-17.38 4.2-24.47-65.02 25.65-6.2 16.2 67.02z"/><path d="M472.85 535.11l-.12-.48a22.23 22.23 0 0116.37-26.8l34-8.23 5.33 22.08z" fill="#2f2e41"/><path fill="#a0616a" d="M443.28 517.91H425.4l-8.5-68.96h26.38v68.96z"/><path d="M447.6 535.01h-57.18v-.5a22.2 22.2 0 0122.2-22.2h34.99zM416.88 490.99l-17.36-206.87 71.86-13.25.28-.05 21.03 13.52-7.32 76.14 33.7 118.7-29.1 7.65-33.75-110.08-7.73-33.48-3.96 43.5 2.94 107.28z" fill="#2f2e41"/><path d="M397.3 288.81l-.2-.24 24.84-186.96.03-.24.17-.18c.37-.36 9.07-8.96 18.02-8.96 1.3 0 2.52-.03 3.7-.06 6.85-.18 12.26-.32 18.69 6.1 6.55 6.56 27.92 30.47 27.92 63.23 0 31.7 2.88 130.22 2.91 131.21l.04 1.4-1.16-.76c-.3-.19-29.03-18.49-53.14-1.48-7.53 5.32-14.3 7.18-20.09 7.18-13.47 0-21.62-10.1-21.73-10.24z" fill="#6c63ff"/><circle cx="737.3" cy="227.82" r="35.82" transform="rotate(-28.66 229.78 725.57)" fill="#a0616a"/><path d="M381.53 328.99a14.66 14.66 0 00.85-22.47l20.34-47.97-26.63 4.9-15.23 44.8A14.74 14.74 0 00381.53 329z" fill="#a0616a"/><path d="M361.88 291.67l6.55-13.83a2.7 2.7 0 01-.97-1c-6.12-10.6 30.84-98.67 33.3-104.51-.37-3.18-4.25-36.85-1.41-48.2 3.34-13.35 10.2-19.58 22.93-20.81 14.04-1.32 17.83 17.75 17.86 17.94l.02 49.02-16.12 56.43-36.75 74.97z" fill="#6c63ff"/><path d="M440.94 58.87c-4.3.56-7.54-3.83-9.04-7.9s-2.64-8.78-6.38-10.98c-5.1-3-11.62.61-17.45-.38-6.59-1.11-10.87-8.1-11.2-14.76s2.31-13.1 4.92-19.24l.9 7.64A15.16 15.16 0 01409.33 0l-1.17 11.22c.73-6.29 7.5-11.16 13.7-9.85l-.19 6.68c7.6-.9 15.28-1.81 22.91-1.12s15.31 3.1 21.1 8.13c8.64 7.51 11.8 19.89 10.74 31.3s-5.77 22.13-10.68 32.48c-1.23 2.6-2.94 5.54-5.8 5.88-2.58.3-4.93-1.86-5.73-4.32s-.41-5.14.07-7.69c.72-3.84 1.63-7.77.95-11.63s-3.45-7.66-7.33-8.13-7.86 3.97-6 7.4z" fill="#2f2e41"/><path fill="#3f3d56" d="M597.73 535.1H339.99v-2.11h258.12l-.38 2.1z"/></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -1,18 +1,17 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import store from "../../store"; import store from "../../store";
import { import { DonorService, DonationService } from "@odit/lfk-client-js";
DonorService
} from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-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 ConfirmDonorDeletion from "./ConfirmDonorDeletion.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 = {};
$: current_donations = [];
$: changes_performed = !( $: changes_performed = !(
JSON.stringify(original_data) === JSON.stringify(editable) JSON.stringify(original_data) === JSON.stringify(editable)
); );
@ -28,25 +27,30 @@
isEmailValid && isEmailValid &&
isPhoneValidOrEmpty && isPhoneValidOrEmpty &&
((isAddress1Valid && iszipcodevalid && iscityvalid) || ((isAddress1Valid && iszipcodevalid && iscityvalid) ||
editable.address_checked === false); editable.address_checked === false);
const promise = DonorService.donorControllerGetOne( const donation_promise = DonationService.donationControllerGetAll().then(
params.donorid (val) => {
).then((data) => { current_donations = val;
data_loaded = true; }
original_data = Object.assign(original_data, data); );
editable = Object.assign(editable, original_data); const promise = DonorService.donorControllerGetOne(params.donorid).then(
editable.address_checked = editable.address.address1 !== null; (data) => {
original_data.address_checked = editable.address.address1 !== null; data_loaded = true;
if(editable.address_checked===false){ original_data = Object.assign(original_data, data);
editable.address = { editable = Object.assign(editable, original_data);
address1: "", editable.address_checked = editable.address.address1 !== null;
address2: "", original_data.address_checked = editable.address.address1 !== null;
city: "", if (editable.address_checked === false) {
postalcode: "", editable.address = {
country: "" address1: "",
address2: "",
city: "",
postalcode: "",
country: "",
};
} }
} }
}); );
$: isPhoneValidOrEmpty = $: isPhoneValidOrEmpty =
editable.phone?.includes("+") || editable.phone?.includes("+") ||
editable.phone === "" || editable.phone === "" ||
@ -59,7 +63,7 @@
function submit() { function submit() {
if (data_loaded === true && save_enabled) { if (data_loaded === true && save_enabled) {
Toastify({ Toastify({
text: $_('donor-is-being-updated'), text: $_("donor-is-being-updated"),
duration: 2500, duration: 2500,
}).showToast(); }).showToast();
editable.address.country = "DE"; editable.address.country = "DE";
@ -73,9 +77,9 @@
DonorService.donorControllerPut(original_data.id, editable) DonorService.donorControllerPut(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;
Toastify({ Toastify({
text: $_('updated-donor'), text: $_("updated-donor"),
duration: 2500, duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
@ -85,13 +89,10 @@
} }
} }
function deleteDonor() { function deleteDonor() {
DonorService.donorControllerRemove( DonorService.donorControllerRemove(original_data.id, false)
original_data.id,
false
)
.then((resp) => { .then((resp) => {
Toastify({ Toastify({
text: $_('donor-deleted'), text: $_("donor-deleted"),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
@ -105,7 +106,7 @@
</script> </script>
<ConfirmDonorDeletion bind:modal_open bind:delete_donor /> <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">
@ -120,8 +121,8 @@
viewBox="0 0 24 24" viewBox="0 0 24 24"
width="24" width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" /> height="24"><path fill="none" d="M0 0h24v24H0z" />
<path <path
d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z" /></svg> d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z" /></svg>
</li> </li>
<li class="flex items-center ml-2"> <li class="flex items-center ml-2">
<a class="mr-2" href="./">{$_('donors')}</a><svg <a class="mr-2" href="./">{$_('donors')}</a><svg
@ -159,12 +160,12 @@
{#if delete_triggered} {#if delete_triggered}
<button <button
on:click={deleteDonor} 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:ml-3 sm:w-auto sm:text-sm">{$_('confirm-deletion')}</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:">{$_('confirm-deletion')}</button>
<button <button
on:click={() => { on:click={() => {
delete_triggered = !delete_triggered; 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> 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:">{$_('cancel')}</button>
{/if} {/if}
{#if !delete_triggered} {#if !delete_triggered}
<button <button
@ -172,7 +173,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:text-sm">{$_('delete-donor')}</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-donor')}</button>
{/if} {/if}
{/if} {/if}
{#if !delete_triggered} {#if !delete_triggered}
@ -181,16 +182,39 @@
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">{$_('save-changes')}</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:">{$_('save-changes')}</button>
{/if} {/if}
</span> </span>
</div> </div>
<!-- --> <!-- -->
<div style="displ"> <div>
<span class="font-medium text-gray-700">{$_('total-donation-amount')}:</span> <span
<span>{(editable.donationAmount/100).toFixed(2).toLocaleString("de-DE", {valute: "EUR"})}</span> class="font-medium text-gray-700">{$_('total-donation-amount')}:</span>
<span>{(editable.donationAmount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}€</span>
<br />
<span class="font-medium text-gray-700">{$_('donations')}:</span>
{#if current_donations.filter((d) => d.donor.id == editable.id).length > 0}
{#each current_donations.filter((o) => o.donor.id == editable.id) as d}
{#if d.responseType === 'DISTANCEDONATION'}
<a
href="../donations/{d.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-600 text-white mr-1">{d.runner.firstname}
{d.runner.middlename}
{d.runner.lastname}</a>
{:else}
<a
href="../donations/{d.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-700 text-white mr-1">{$_('fixed-donation')}:
{(d.amount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}€</a>
{/if}
{/each}
{:else}{$_('donor-has-no-associated-donations')}{/if}
</div> </div>
<div class="text-sm w-full"> <div class=" w-full">
<label <label
for="firstname" for="firstname"
class="font-medium text-gray-700">{$_('first-name')}</label> class="font-medium text-gray-700">{$_('first-name')}</label>
@ -203,7 +227,7 @@
class:focus:ring-red-500={!isFirstnameValid} class:focus:ring-red-500={!isFirstnameValid}
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: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !isFirstnameValid} {#if !isFirstnameValid}
<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">
@ -211,7 +235,7 @@
</span> </span>
{/if} {/if}
</div> </div>
<div class="text-sm w-full"> <div class=" w-full">
<label <label
for="middlename" for="middlename"
class="font-medium text-gray-700">{$_('middle-name')}</label> class="font-medium text-gray-700">{$_('middle-name')}</label>
@ -221,9 +245,9 @@
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: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div> </div>
<div class="text-sm w-full"> <div class=" w-full">
<label <label
for="lastname" for="lastname"
class="font-medium text-gray-700">{$_('last-name')}</label> class="font-medium text-gray-700">{$_('last-name')}</label>
@ -236,7 +260,7 @@
class:focus:border-red-500={!isLastnameValid} class:focus:border-red-500={!isLastnameValid}
class:focus:ring-red-500={!isLastnameValid} class:focus:ring-red-500={!isLastnameValid}
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: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !isLastnameValid} {#if !isLastnameValid}
<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">
@ -244,7 +268,7 @@
</span> </span>
{/if} {/if}
</div> </div>
<div class="text-sm w-full"> <div class=" w-full">
<label <label
for="email" for="email"
class="font-medium text-gray-700">{$_('e-mail-adress')}</label> class="font-medium text-gray-700">{$_('e-mail-adress')}</label>
@ -257,7 +281,7 @@
class:focus:border-red-500={!isEmailValid} class:focus:border-red-500={!isEmailValid}
class:focus:ring-red-500={!isEmailValid} class:focus:ring-red-500={!isEmailValid}
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: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !isEmailValid} {#if !isEmailValid}
<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">
@ -265,7 +289,7 @@
</span> </span>
{/if} {/if}
</div> </div>
<div class="text-sm w-full"> <div class=" w-full">
<label for="phone" class="font-medium text-gray-700">{$_('phone')}</label> <label for="phone" class="font-medium text-gray-700">{$_('phone')}</label>
<input <input
autocomplete="off" autocomplete="off"
@ -276,7 +300,7 @@
class:focus:ring-red-500={!isPhoneValidOrEmpty} class:focus:ring-red-500={!isPhoneValidOrEmpty}
bind:value={editable.phone} bind:value={editable.phone}
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: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !isPhoneValidOrEmpty} {#if !isPhoneValidOrEmpty}
<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">
@ -293,7 +317,7 @@
type="checkbox" type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" /> class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" />
</div> </div>
<div class="ml-3 text-sm"> <div class="ml-3 ">
<label <label
for="comments" for="comments"
class="font-medium text-gray-700">{$_('receipt-needed')}</label> class="font-medium text-gray-700">{$_('receipt-needed')}</label>
@ -303,7 +327,7 @@
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="address1" for="address1"
class="block text-sm font-medium text-gray-700">{$_('address')}</label> class="block font-medium text-gray-700">{$_('address')}</label>
<input <input
autocomplete="off" autocomplete="off"
placeholder="Address" placeholder="Address"
@ -313,7 +337,7 @@
bind:value={editable.address.address1} bind:value={editable.address.address1}
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: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !isAddress1Valid} {#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">
@ -324,19 +348,19 @@
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="address2" for="address2"
class="block text-sm font-medium text-gray-700">{$_('apartment-suite-etc')}</label> class="block font-medium text-gray-700">{$_('apartment-suite-etc')}</label>
<input <input
autocomplete="off" autocomplete="off"
placeholder={$_('apartment-suite-etc')} placeholder={$_('apartment-suite-etc')}
bind:value={editable.address.address2} bind:value={editable.address.address2}
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: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
</div> </div>
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="zipcode" for="zipcode"
class="block text-sm font-medium text-gray-700">{$_('zip-postal-code')}</label> class="block font-medium text-gray-700">{$_('zip-postal-code')}</label>
<input <input
autocomplete="off" autocomplete="off"
placeholder={$_('zip-postal-code')} placeholder={$_('zip-postal-code')}
@ -346,7 +370,7 @@
bind:value={editable.address.postalcode} bind:value={editable.address.postalcode}
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: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !iszipcodevalid} {#if !iszipcodevalid}
<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">
@ -357,7 +381,7 @@
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="city" for="city"
class="block text-sm font-medium text-gray-700">{$_('city')}</label> class="block font-medium text-gray-700">{$_('city')}</label>
<input <input
autocomplete="off" autocomplete="off"
placeholder={$_('city')} placeholder={$_('city')}
@ -367,7 +391,7 @@
bind:value={editable.address.city} bind:value={editable.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: border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2" />
{#if !iscityvalid} {#if !iscityvalid}
<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">

View File

@ -1,18 +1,24 @@
<script> <script>
import { getLocaleFromNavigator, _ } from "svelte-i18n"; import { getLocaleFromNavigator, _ } from "svelte-i18n";
import { DonorService } from "@odit/lfk-client-js"; import { DonationService, DonorService } from "@odit/lfk-client-js";
import store from "../../store"; import store from "../../store";
import DonorsEmptyState from "./DonorsEmptyState.svelte"; import DonorsEmptyState from "./DonorsEmptyState.svelte";
import ConfirmDonorDeletion from "./ConfirmDonorDeletion.svelte"; import ConfirmDonorDeletion from "./ConfirmDonorDeletion.svelte";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
$: searchvalue = ""; $: searchvalue = "";
$: active_deletes = []; $: active_deletes = [];
$: current_donations = [];
let modal_open = false; let modal_open = false;
let delete_donor = {}; let delete_donor = {};
export let current_donors = []; export let current_donors = [];
const donors_promise = DonorService.donorControllerGetAll().then((val) => { const donors_promise = DonorService.donorControllerGetAll().then((val) => {
current_donors = val; current_donors = val;
}); });
const donation_promise = DonationService.donationControllerGetAll().then(
(val) => {
current_donations = val;
}
);
function should_display_based_on_id(id) { function should_display_based_on_id(id) {
if (searchvalue.toString().slice(-1) === "*") { if (searchvalue.toString().slice(-1) === "*") {
return id.toString().startsWith(searchvalue.replace("*", "")); return id.toString().startsWith(searchvalue.replace("*", ""));
@ -29,7 +35,7 @@
bind:modal_open bind:modal_open
bind:delete_donor /> bind:delete_donor />
{#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:GET')} {#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:GET')}
{#await donors_promise} {#await donors_promise && donation_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">
@ -118,9 +124,30 @@
{donor.address.country} {donor.address.country}
{/if} {/if}
</td> </td>
<td class="px-6 py-4 whitespace-nowrap">TODO</td>
<td class="px-6 py-4 whitespace-nowrap"> <td class="px-6 py-4 whitespace-nowrap">
{(donor.donationAmount/100).toFixed(2).toLocaleString("de-DE", {valute: "EUR"})} {#if current_donations.filter((d) => d.donor.id == donor.id).length > 0}
{#each current_donations.filter((o) => o.donor.id == donor.id) as d}
{#if d.responseType === 'DISTANCEDONATION'}
<a
href="../donations/{d.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-600 text-white mr-1">{d.runner.firstname}
{d.runner.middlename}
{d.runner.lastname}</a>
{:else}
<a
href="../donations/{d.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-700 text-white mr-1">{$_('fixed-donation')}:
{(d.amount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}€</a>
{/if}
{/each}
{:else}{$_('donor-has-no-associated-donations')}{/if}
</td>
<td class="px-6 py-4 whitespace-nowrap">
{(donor.donationAmount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}€
</td> </td>
{#if active_deletes[donor.id] === true} {#if active_deletes[donor.id] === true}
<td <td

View File

@ -4,6 +4,7 @@
"about": "Über", "about": "Über",
"action": "Aktionen", "action": "Aktionen",
"active": "Aktiv", "active": "Aktiv",
"add-donation": "Sponsoring erstellen",
"add-donor": "Sponsor:in erstellen", "add-donor": "Sponsor:in erstellen",
"add-your-first-contact": "Erstelle den ersten Kontakt", "add-your-first-contact": "Erstelle den ersten Kontakt",
"add-your-first-donor": "Erstelle die erste Sponsor:in", "add-your-first-donor": "Erstelle die erste Sponsor:in",
@ -17,6 +18,7 @@
"all-associated-donations-will-get-deleted-as-well": "Alle Sponsorings dieser Sponsor:in werden ebenfalls gelöscht", "all-associated-donations-will-get-deleted-as-well": "Alle Sponsorings dieser Sponsor:in werden ebenfalls gelöscht",
"all-associated-runners-will-be-deleted-too": "Alle zugehörigen Läufer:innen werden auch gelöscht!", "all-associated-runners-will-be-deleted-too": "Alle zugehörigen Läufer:innen werden auch gelöscht!",
"all-associated-teams-and-runners-will-be-deleted-too": "Alle assoziierten Teams und Läufer:innen werden auch gelöscht!", "all-associated-teams-and-runners-will-be-deleted-too": "Alle assoziierten Teams und Läufer:innen werden auch gelöscht!",
"amount-per-kilometer": "Betrag pro Kilometer",
"apartment-suite-etc": "Apartment, Wohnung, etc.", "apartment-suite-etc": "Apartment, Wohnung, etc.",
"application_name": "Lauf für Kaya! - Admin", "application_name": "Lauf für Kaya! - Admin",
"applying-changes": "Änderungen anwenden", "applying-changes": "Änderungen anwenden",
@ -49,8 +51,11 @@
"count_organizations": "Organisationen (Anzahl)", "count_organizations": "Organisationen (Anzahl)",
"count_teams": "Teams (Anzahl)", "count_teams": "Teams (Anzahl)",
"create": "Erstellen", "create": "Erstellen",
"create-a-new": "Erstelle eine neue",
"create-a-new-contact": "Kontakt erstellen", "create-a-new-contact": "Kontakt erstellen",
"create-a-new-distance-donation": "Erstelle ein neues Sponsoring",
"create-a-new-donor": "Neue Sponsor:in erstellen", "create-a-new-donor": "Neue Sponsor:in erstellen",
"create-a-new-fixed-donation": "Erstelle eine neue Festbetragsspende",
"create-a-new-organization": "Neue Organisation anlegen", "create-a-new-organization": "Neue Organisation anlegen",
"create-a-new-runner": "Neue Läufer:in erstellen", "create-a-new-runner": "Neue Läufer:in erstellen",
"create-a-new-team": "Erstelle ein neues Team", "create-a-new-team": "Erstelle ein neues Team",
@ -85,6 +90,7 @@
}, },
"delete": "Löschen", "delete": "Löschen",
"delete-contact": "Kontakt löschen", "delete-contact": "Kontakt löschen",
"delete-donation": "Sponsporing löschen",
"delete-donor": "Sponsor:in löschen", "delete-donor": "Sponsor:in löschen",
"delete-organization": "Organisation löschen", "delete-organization": "Organisation löschen",
"delete-runner": "Läufer:in löschen", "delete-runner": "Läufer:in löschen",
@ -94,13 +100,18 @@
"deselect-all": "Alle abwählen", "deselect-all": "Alle abwählen",
"details": "Details", "details": "Details",
"distance": "Distanz", "distance": "Distanz",
"distance-donation": "Sponsoring",
"distance-in-km": "Distanz (in KM)", "distance-in-km": "Distanz (in KM)",
"do-you-want-to-delete-the-organization-delete_org-name": "Möchtest du die Organisation {orgname} löschen?", "do-you-want-to-delete-the-organization-delete_org-name": "Möchtest du die Organisation {orgname} löschen?",
"do-you-want-to-delete-the-team-delete_team-name": "Möchtest du das Team {teamname} löschen?", "do-you-want-to-delete-the-team-delete_team-name": "Möchtest du das Team {teamname} löschen?",
"do-you-want-to-delete-this-donor-with-all-related-donations": "Möchtest du diese Sponsor:in mit all ihren Sponsorings löschen?", "do-you-want-to-delete-this-donor-with-all-related-donations": "Möchtest du diese Sponsor:in mit all ihren Sponsorings löschen?",
"donation-amount": "Sponsoringbetrag",
"donation-amount-must-be-greater-that-0-00eur": "Der Sponsoringbetrag muss größer als 0.00€ sein.",
"donations": "Sponsorings", "donations": "Sponsorings",
"donor": "Sponsor:in",
"donor-added": "Sponsor:in hinzugefügt", "donor-added": "Sponsor:in hinzugefügt",
"donor-deleted": "Sponsor:in gelöscht", "donor-deleted": "Sponsor:in gelöscht",
"donor-has-no-associated-donations": "Zur Sponsor:in gibt es noch keine Sponsorings",
"donor-is-being-added": "Sponsor:in wird hinzugefügt...", "donor-is-being-added": "Sponsor:in wird hinzugefügt...",
"donor-is-being-updated": "Sponsor:in wird aktualisiert", "donor-is-being-updated": "Sponsor:in wird aktualisiert",
"donors": "Sponsor:innen", "donors": "Sponsor:innen",
@ -118,6 +129,7 @@
"filter-by-organization-team": "Filtern nach Organisation / Team", "filter-by-organization-team": "Filtern nach Organisation / Team",
"first-name": "Vorname", "first-name": "Vorname",
"first-name-is-required": "Vorname muss angegeben werden", "first-name-is-required": "Vorname muss angegeben werden",
"fixed-donation": "Festbetragsspende",
"forgot_password": "Passwort vergessen?", "forgot_password": "Passwort vergessen?",
"geerbte": "geerbte", "geerbte": "geerbte",
"general-stats": "Allgemeine Statistiken", "general-stats": "Allgemeine Statistiken",
@ -150,6 +162,7 @@
"license": "Lizenz", "license": "Lizenz",
"licenses-are-being-loaded": "Lizenzen werden geladen...", "licenses-are-being-loaded": "Lizenzen werden geladen...",
"loading-contact-details": "Kontaktdaten werden geladen ...", "loading-contact-details": "Kontaktdaten werden geladen ...",
"loading-donation-details": "Lade Sponsoringdetails",
"loading-donor-details": "Lade Details", "loading-donor-details": "Lade Details",
"loading-runners": "Läufer:innen werden geladen...", "loading-runners": "Läufer:innen werden geladen...",
"log_in": "Anmelden", "log_in": "Anmelden",
@ -186,11 +199,13 @@
"pdf-generation-failed": "PDF Generierung fehlgeschlagen!", "pdf-generation-failed": "PDF Generierung fehlgeschlagen!",
"pdf-successfully-generated": "PDF wurde erfolgreich generiert!", "pdf-successfully-generated": "PDF wurde erfolgreich generiert!",
"pdfs-successfully-generated": "Alle PDFs wurden generiert!", "pdfs-successfully-generated": "Alle PDFs wurden generiert!",
"per-kilometer": "pro Kilometer",
"permissions": "Berechtigungen", "permissions": "Berechtigungen",
"permissions-updated": "Berechtigungen aktualisiert!", "permissions-updated": "Berechtigungen aktualisiert!",
"phone": "Telefon", "phone": "Telefon",
"please-provide-a-password": "Bitte gebe ein Passwort an...", "please-provide-a-password": "Bitte gebe ein Passwort an...",
"please-provide-the-nessecary-information-to-add-a-new-donor": "Bitte mach die Notwendigen Angaben, um eine neue Sponsor:in zu erstellen", "please-provide-the-nessecary-information-to-add-a-new-donor": "Bitte mach die Notwendigen Angaben, um eine neue Sponsor:in zu erstellen",
"please-provide-the-nessecary-information-to-create-a-new-donation": "Bitte gebe alle für das Sponsoring notwendigen Daten an.",
"please-provide-the-required-csv-xlsx-file": "Bitte eine CSV oder XLSX Datei hochladen.", "please-provide-the-required-csv-xlsx-file": "Bitte eine CSV oder XLSX Datei hochladen.",
"please-provide-the-required-information-to-add-a-new-contact": "Bitte gebe alle nötigen Informationen an, im den neuen Kontakt zu erstellen.", "please-provide-the-required-information-to-add-a-new-contact": "Bitte gebe alle nötigen Informationen an, im den neuen Kontakt zu erstellen.",
"please-provide-the-required-information-to-add-a-new-organization": "Bitte gebe alle nötigen Informationen an, im die neue Organisation zu erstellen.", "please-provide-the-required-information-to-add-a-new-organization": "Bitte gebe alle nötigen Informationen an, im die neue Organisation zu erstellen.",
@ -208,6 +223,7 @@
"request-a-new-reset-mail": "Neue Reset-Mail anfordern", "request-a-new-reset-mail": "Neue Reset-Mail anfordern",
"reset-my-password": "Passwort zurücksetzen", "reset-my-password": "Passwort zurücksetzen",
"reset-password": "Passwort zurücksetzen", "reset-password": "Passwort zurücksetzen",
"runner": "Läufer:in",
"runner-added": "Läufer:in hinzugefügt", "runner-added": "Läufer:in hinzugefügt",
"runner-import": "Läufer:innen Import", "runner-import": "Läufer:innen Import",
"runner-is-being-added": "Läufer:in wird hinzugefügt...", "runner-is-being-added": "Läufer:in wird hinzugefügt...",
@ -239,7 +255,7 @@
"there-are-no-users-added-yet": "Es wurden noch keine Benutzer hinzugefügt.", "there-are-no-users-added-yet": "Es wurden noch keine Benutzer hinzugefügt.",
"this-might-take-a-moment": "Das könnte einen kleinen Moment dauern", "this-might-take-a-moment": "Das könnte einen kleinen Moment dauern",
"total-distance": "gelaufene Strecke", "total-distance": "gelaufene Strecke",
"total-donation-amount": "Gesamte Spenden", "total-donation-amount": "Gesamtbetrag",
"total-donations": "Spendensumme", "total-donations": "Spendensumme",
"total-scans": "gesamte Scans", "total-scans": "gesamte Scans",
"track-added": "Track hinzugefügt", "track-added": "Track hinzugefügt",

View File

@ -4,6 +4,7 @@
"about": "About", "about": "About",
"action": "Action", "action": "Action",
"active": "Active", "active": "Active",
"add-donation": "Add donation",
"add-donor": "add donor", "add-donor": "add donor",
"add-your-first-contact": "Add your first contact", "add-your-first-contact": "Add your first contact",
"add-your-first-donor": "add your first donor", "add-your-first-donor": "add your first donor",
@ -17,6 +18,7 @@
"all-associated-donations-will-get-deleted-as-well": "All associated donations will get deleted as well", "all-associated-donations-will-get-deleted-as-well": "All associated donations will get deleted as well",
"all-associated-runners-will-be-deleted-too": "All associated runners will be deleted too!", "all-associated-runners-will-be-deleted-too": "All associated runners will be deleted too!",
"all-associated-teams-and-runners-will-be-deleted-too": "All associated teams and runners will be deleted too!", "all-associated-teams-and-runners-will-be-deleted-too": "All associated teams and runners will be deleted too!",
"amount-per-kilometer": "Amount per kilometer",
"apartment-suite-etc": "Apartment, suite, etc.", "apartment-suite-etc": "Apartment, suite, etc.",
"application_name": "Lauf für Kaya! - Admin", "application_name": "Lauf für Kaya! - Admin",
"applying-changes": "Applying Changes", "applying-changes": "Applying Changes",
@ -49,8 +51,11 @@
"count_organizations": "# Organizations", "count_organizations": "# Organizations",
"count_teams": "# Teams", "count_teams": "# Teams",
"create": "Create", "create": "Create",
"create-a-new": "Create a new",
"create-a-new-contact": "Create a new contact", "create-a-new-contact": "Create a new contact",
"create-a-new-distance-donation": "Create a new distance donation",
"create-a-new-donor": "Create a new donor", "create-a-new-donor": "Create a new donor",
"create-a-new-fixed-donation": "Create a new fixed donation",
"create-a-new-organization": "Create a new Organization", "create-a-new-organization": "Create a new Organization",
"create-a-new-runner": "Create a new Runner", "create-a-new-runner": "Create a new Runner",
"create-a-new-team": "Create a new team", "create-a-new-team": "Create a new team",
@ -85,6 +90,7 @@
}, },
"delete": "Delete", "delete": "Delete",
"delete-contact": "Delete Contact", "delete-contact": "Delete Contact",
"delete-donation": "Delete Donation",
"delete-donor": "Delete donor", "delete-donor": "Delete donor",
"delete-organization": "Delete Organization", "delete-organization": "Delete Organization",
"delete-runner": "Delete Runner", "delete-runner": "Delete Runner",
@ -94,13 +100,18 @@
"deselect-all": "deselect all", "deselect-all": "deselect all",
"details": "Details", "details": "Details",
"distance": "Distance", "distance": "Distance",
"distance-donation": "distance donation",
"distance-in-km": "Distance in km", "distance-in-km": "Distance in km",
"do-you-want-to-delete-the-organization-delete_org-name": "Do you want to delete the organization {orgname}?", "do-you-want-to-delete-the-organization-delete_org-name": "Do you want to delete the organization {orgname}?",
"do-you-want-to-delete-the-team-delete_team-name": "Do you want to delete the team {teamname}?", "do-you-want-to-delete-the-team-delete_team-name": "Do you want to delete the team {teamname}?",
"do-you-want-to-delete-this-donor-with-all-related-donations": "Do you want to delete this donor with all related donations", "do-you-want-to-delete-this-donor-with-all-related-donations": "Do you want to delete this donor with all related donations",
"donation-amount": "Donation amount",
"donation-amount-must-be-greater-that-0-00eur": "Donation amount must be greater that 0.00€",
"donations": "Donations", "donations": "Donations",
"donor": "Donor",
"donor-added": "Donor added", "donor-added": "Donor added",
"donor-deleted": "donor deleted", "donor-deleted": "donor deleted",
"donor-has-no-associated-donations": "Donor has no associated donations.",
"donor-is-being-added": "Donor is being added...", "donor-is-being-added": "Donor is being added...",
"donor-is-being-updated": "Donor is being updated", "donor-is-being-updated": "Donor is being updated",
"donors": "Donors", "donors": "Donors",
@ -118,6 +129,7 @@
"filter-by-organization-team": "Filter by Organization/ Team", "filter-by-organization-team": "Filter by Organization/ Team",
"first-name": "First name", "first-name": "First name",
"first-name-is-required": "First Name is required", "first-name-is-required": "First Name is required",
"fixed-donation": "fixed donation",
"forgot_password": "Forgot your password?", "forgot_password": "Forgot your password?",
"geerbte": "inherited", "geerbte": "inherited",
"general-stats": "General Stats", "general-stats": "General Stats",
@ -150,6 +162,7 @@
"license": "License", "license": "License",
"licenses-are-being-loaded": "Licenses are being loaded...", "licenses-are-being-loaded": "Licenses are being loaded...",
"loading-contact-details": "Loading contact details...", "loading-contact-details": "Loading contact details...",
"loading-donation-details": "Loading donation details",
"loading-donor-details": "Loading donor details", "loading-donor-details": "Loading donor details",
"loading-runners": "loading runners...", "loading-runners": "loading runners...",
"log_in": "Log in", "log_in": "Log in",
@ -186,11 +199,13 @@
"pdf-generation-failed": "PDF generation failed!", "pdf-generation-failed": "PDF generation failed!",
"pdf-successfully-generated": "PDF successfully generated!", "pdf-successfully-generated": "PDF successfully generated!",
"pdfs-successfully-generated": "PDFs successfully generated!", "pdfs-successfully-generated": "PDFs successfully generated!",
"per-kilometer": "per Kilometer",
"permissions": "Permissions", "permissions": "Permissions",
"permissions-updated": "Permissions updated!", "permissions-updated": "Permissions updated!",
"phone": "Phone", "phone": "Phone",
"please-provide-a-password": "Please provide a password...", "please-provide-a-password": "Please provide a password...",
"please-provide-the-nessecary-information-to-add-a-new-donor": "Please provide the nessecary information to add a new donor", "please-provide-the-nessecary-information-to-add-a-new-donor": "Please provide the nessecary information to add a new donor",
"please-provide-the-nessecary-information-to-create-a-new-donation": "Please provide the nessecary information to create a new donation",
"please-provide-the-required-csv-xlsx-file": "Please provide the required csv/ xlsx file", "please-provide-the-required-csv-xlsx-file": "Please provide the required csv/ xlsx file",
"please-provide-the-required-information-to-add-a-new-contact": "Please provide the required information to add a new contact.", "please-provide-the-required-information-to-add-a-new-contact": "Please provide the required information to add a new contact.",
"please-provide-the-required-information-to-add-a-new-organization": "Please provide the required information to add a new organization.", "please-provide-the-required-information-to-add-a-new-organization": "Please provide the required information to add a new organization.",
@ -208,6 +223,7 @@
"request-a-new-reset-mail": "Request a new reset mail", "request-a-new-reset-mail": "Request a new reset mail",
"reset-my-password": "Reset my password", "reset-my-password": "Reset my password",
"reset-password": "Reset your password", "reset-password": "Reset your password",
"runner": "Runner",
"runner-added": "Runner added", "runner-added": "Runner added",
"runner-import": "Runner Import", "runner-import": "Runner Import",
"runner-is-being-added": "Runner is being added...", "runner-is-being-added": "Runner is being added...",