Compare commits

...

2 Commits

Author SHA1 Message Date
5dcb4cb508
chore(release): 1.12.0
All checks were successful
Build release images / build-container (push) Successful in 1m10s
2025-04-28 11:05:59 +02:00
9c03e359a4
feat: anonymous donations
commit 8c56aa3c460595a5706d5c0d4bf020d74d5cdd67
Merge: f642849d 1505080a
Author: Philipp Dormann <philipp@philippdormann.de>
Date:   Mon Apr 28 10:57:14 2025 +0200

    Merge branch 'dev' into feature/anonyme-spende

commit f642849dbbd6e68198937fe2d9e588e0ddeb9fdb
Author: Philipp Dormann <philipp@philippdormann.de>
Date:   Mon Apr 28 10:56:45 2025 +0200

    wip

commit 7ac92ae6ca310c9e4d5ed3fb38f8b5eb93949809
Author: Philipp Dormann <philipp@philippdormann.de>
Date:   Mon Apr 28 10:45:47 2025 +0200

    wip

commit 95af9f9914883e3d8a272f89b7c11c4a6802a416
Author: Philipp Dormann <philipp@philippdormann.de>
Date:   Mon Apr 28 10:44:02 2025 +0200

    i18n

commit 1004aee16c61411489f0231366ee94fdc16f21b2
Author: Philipp Dormann <philipp@philippdormann.de>
Date:   Mon Apr 28 10:40:23 2025 +0200

    implement DonationDonor

commit 0baf2fc460178cf8c6fa193547417e8d25f227a1
Author: Philipp Dormann <philipp@philippdormann.de>
Date:   Mon Apr 28 10:38:27 2025 +0200

    wip

commit 09b59175eeffe6026a4b48ee3d2f94a83f9dbf09
Author: Philipp Dormann <philipp@philippdormann.de>
Date:   Mon Apr 28 10:35:45 2025 +0200

    wip

commit a21f61f3f390d506a9046e17f9f49ba70cfc04b6
Author: Philipp Dormann <philipp@philippdormann.de>
Date:   Mon Apr 28 10:24:07 2025 +0200

    wip
2025-04-28 11:05:40 +02:00
8 changed files with 415 additions and 346 deletions

View File

@ -2,8 +2,16 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC. All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [1.12.0](https://git.odit.services/lfk/frontend/compare/1.11.5...1.12.0)
- feat: anonymous donations [`9c03e35`](https://git.odit.services/lfk/frontend/commit/9c03e359a4e8f43452475b02bcabcb354987ab75)
- refactor: use modern tailwindcss features [`1505080`](https://git.odit.services/lfk/frontend/commit/1505080afdd8b272b76584e2777df732001ce004)
#### [1.11.5](https://git.odit.services/lfk/frontend/compare/1.11.4...1.11.5) #### [1.11.5](https://git.odit.services/lfk/frontend/compare/1.11.4...1.11.5)
> 25 April 2025
- chore(release): 1.11.5 [`8cb6093`](https://git.odit.services/lfk/frontend/commit/8cb6093f0b3474c0952a8a51a47683262fc31f8f)
- fix(cards): Update table for edit events [`27396e1`](https://git.odit.services/lfk/frontend/commit/27396e17f2cd8be72c9c8100afe6ec75ac66dceb) - fix(cards): Update table for edit events [`27396e1`](https://git.odit.services/lfk/frontend/commit/27396e17f2cd8be72c9c8100afe6ec75ac66dceb)
#### [1.11.4](https://git.odit.services/lfk/frontend/compare/1.11.3...1.11.4) #### [1.11.4](https://git.odit.services/lfk/frontend/compare/1.11.3...1.11.4)

View File

@ -13,7 +13,7 @@
<body> <body>
<span style="display: none; visibility: hidden" id="buildinfo" <span style="display: none; visibility: hidden" id="buildinfo"
>RELEASE_INFO-1.11.5-RELEASE_INFO</span >RELEASE_INFO-1.12.0-RELEASE_INFO</span
> >
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<script src="/env.js"></script> <script src="/env.js"></script>

View File

@ -1,6 +1,6 @@
{ {
"name": "@odit/lfk-frontend", "name": "@odit/lfk-frontend",
"version": "1.11.5", "version": "1.12.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"i18n-order": "node order.js", "i18n-order": "node order.js",

View File

@ -21,7 +21,7 @@
$: runner = 0; $: runner = 0;
$: donors = []; $: donors = [];
$: runners = []; $: runners = [];
$: is_fixed = false; $: type = "distance";
$: is_paid = false; $: is_paid = false;
$: amount_input = 0; $: amount_input = 0;
$: processed_last_submit = true; $: processed_last_submit = true;
@ -46,7 +46,7 @@
let amount_cent = Math.floor(amount_input * 100); let amount_cent = Math.floor(amount_input * 100);
processed_last_submit = false; processed_last_submit = false;
toast.loading($_("adding-donation")); toast.loading($_("adding-donation"));
if (is_fixed) { if (type === "fixed") {
let postdata = { let postdata = {
donor, donor,
amount: amount_cent, amount: amount_cent,
@ -72,7 +72,30 @@
.finally(() => { .finally(() => {
processed_last_submit = true; processed_last_submit = true;
}); });
} else { } else if (type === "anonymous") {
let postdata = {
amount: amount_cent,
paidAmount: 0,
};
if (is_paid) {
postdata.paidAmount = amount_cent;
}
DonationService.donationControllerPostFixed(postdata)
.then((result) => {
amount_input = 0;
modal_open = false;
//
toast.dismiss();
toast.success($_("donation_added"));
dispatch("created", { donations: [result] });
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
});
} else if (type === "distance") {
let postdata = { let postdata = {
donor, donor,
runner, runner,
@ -100,16 +123,12 @@
} }
onMount(async () => { onMount(async () => {
donors = (await DonorService.donorControllerGetAll()).map( donors = (await DonorService.donorControllerGetAll()).map((r) => {
(r) => {
return { label: getDonorLabel(r), value: r }; return { label: getDonorLabel(r), value: r };
} });
); runners = (await RunnerService.runnerControllerGetAll()).map((r) => {
runners = (await RunnerService.runnerControllerGetAll()).map(
(r) => {
return { label: getDonorLabel(r), value: r }; return { label: getDonorLabel(r), value: r };
} });
);
}); });
</script> </script>
@ -126,7 +145,7 @@
> >
<div class="fixed inset-0 transition-opacity" aria-hidden="true"> <div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div <div
class="absolute inset-0 bg-gray-500 opacity-75" class="absolute inset-0 bg-neutral-500 opacity-75"
data-id="modal_backdrop" data-id="modal_backdrop"
/> />
</div> </div>
@ -146,7 +165,7 @@
class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10" class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
> >
<svg <svg
class="h-6 w-6 text-blue-600" class="size-6 text-blue-600"
fill="currentColor" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" viewBox="0 0 24 24"
@ -159,40 +178,97 @@
> >
</div> </div>
<div class="mt-3"> <div class="mt-3">
<h3 class="text-lg leading-6 font-medium text-gray-900"> <h3 class="text-xl leading-6 font-medium text-neutral-900">
{#if is_fixed} Sponsoring erstellen
{$_("create-a-new-fixed-donation")}
{:else}{$_("create-a-new-distance-donation")}{/if}
</h3> </h3>
<label class="content-center align-middle object-center"> <nav
<span class="text-base" class:text-gray-300={is_fixed} class="relative z-0 flex border border-neutral-200 rounded-xl overflow-hidden mb-2"
>{$_("distance-donation")}</span
> >
<input <button
class="toggle 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" on:click={() => {
type="checkbox" type = "distance";
bind:checked={is_fixed} }}
/> type="button"
<span class="ml-2 text-base" class:text-gray-300={!is_fixed} id="bar-with-underline-item-1"
>{$_("fixed-donation")}</span class:donation_active_tab={type === "distance"}
class:donation_inactive_tab={type !== "distance"}
aria-selected={type === "distance"}
role="tab"
> >
</label> {$_("spende_pro_km")}
<div class="mb-6"> </button>
<p class="text-sm text-gray-500"> <button
{$_( on:click={() => {
"please-provide-the-nessecary-information-to-create-a-new-donation" type = "fixed";
)} }}
</p> type="button"
</div> id="bar-with-underline-item-2"
class:donation_active_tab={type === "fixed"}
class:donation_inactive_tab={type !== "fixed"}
aria-selected={type === "fixed"}
role="tab"
>
{$_("festbetrag")}
</button>
<button
on:click={() => {
type = "anonymous";
}}
type="button"
id="bar-with-underline-item-3"
class:donation_active_tab={type === "anonymous"}
class:donation_inactive_tab={type !== "anonymous"}
aria-selected={type === "anonymous"}
role="tab"
>
{$_("anonyme_spende")}
</button>
</nav>
<div class="grid grid-cols-6 gap-2 lg:gap-6 text-left"> <div class="grid grid-cols-6 gap-2 lg:gap-6 text-left">
{#if type === "anonymous"}
<div class="col-span-6">
<label
for="donation_amount_eur"
class="block text-sm font-medium text-neutral-900"
>
{$_("donation-amount")}</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-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>
{#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>
{:else}
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="donor" for="donor"
class="block text-sm font-medium text-gray-700" class="block text-sm font-medium text-neutral-900"
>{$_("donor")}</label >{$_("donor")}</label
> >
<Select <Select
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 rounded-md p-2"
itemFilter={(label, filterText, option) => itemFilter={(label, filterText, option) =>
filterDonors(label, filterText, option)} filterDonors(label, filterText, option)}
items={donors} items={donors}
@ -204,15 +280,15 @@
on:clear={() => (donors = null)} on:clear={() => (donors = null)}
/> />
</div> </div>
{#if !is_fixed} {#if type === "distance"}
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="donor" for="donor"
class="block text-sm font-medium text-gray-700" class="block text-sm font-medium text-neutral-900"
>{$_("runner")}</label >{$_("runner")}</label
> >
<Select <Select
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2" containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 rounded-md p-2"
itemFilter={(label, filterText, option) => itemFilter={(label, filterText, option) =>
filterDonors(label, filterText, option)} filterDonors(label, filterText, option)}
items={runners} items={runners}
@ -228,11 +304,11 @@
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="donation_amount_eur" for="donation_amount_eur"
class="block text-sm font-medium text-gray-700" class="block text-sm font-medium text-neutral-900"
> >
{#if !is_fixed} {#if type === "fixed"}
{$_("amount-per-kilometer")} {$_("donation-amount")}
{:else}{$_("donation-amount")}{/if}</label {:else}{$_("amount-per-kilometer")}{/if}</label
> >
<div class="mt-1 flex rounded-md shadow-sm"> <div class="mt-1 flex rounded-md shadow-sm">
<input <input
@ -244,11 +320,11 @@
type="number" type="number"
step="0.01" step="0.01"
name="donation_amount_eur" name="donation_amount_eur"
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 p-2" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-neutral-300 border bg-neutral-50 text-neutral-800 p-2"
placeholder="2.00" placeholder="2.00"
/> />
<span <span
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm" class="inline-flex items-center px-3 rounded-r-md border border-neutral-300 bg-neutral-50 text-neutral-500 text-sm"
>€</span >€</span
> >
</div> </div>
@ -260,36 +336,29 @@
</span> </span>
{/if} {/if}
</div> </div>
{#if is_fixed} {/if}
<div class="col-span-6"> {#if type === "fixed" || type === "anonymous"}
<div class="flex">
<input
bind:checked={is_paid}
type="checkbox"
class="shrink-0 mt-0.5 border-neutral-200 rounded-sm text-blue-600 focus:ring-blue-500 checked:border-blue-500 disabled:opacity-50 disabled:pointer-events-none"
id="hs-default-checkbox"
/>
<label <label
for="paid" for="hs-default-checkbox"
class="block text-sm font-medium text-gray-700" class="text-base text-neutral-900 ms-2 font-medium"
>{$_("already-paid")}</label >{$_("already-paid")}</label
> >
<p class="text-gray-500">
<input
id="paid"
bind:checked={is_paid}
name="paid"
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
<span class="align-text-bottom">
{#if is_paid}
{$_("paid")}
{:else}
{$_("open")}
{/if}
</span>
</p>
</div> </div>
{/if} {/if}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="bg-gray-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"> <div
class="bg-neutral-50 px-4 lg:py-3 sm:px-6 grid gap-2 lg:rounded-b-xl pt-3 pb-10"
>
<button <button
disabled={!createbtnenabled} disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled} class:opacity-50={!createbtnenabled}
@ -304,7 +373,7 @@
modal_open = false; modal_open = false;
}} }}
type="button" type="button"
class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block" class="w-full justify-center rounded-md border border-neutral-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-neutral-900 hover:bg-neutral-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block"
> >
{$_("cancel")} {$_("cancel")}
</button> </button>
@ -313,28 +382,3 @@
</div> </div>
</div> </div>
{/if} {/if}
<style>
.toggle: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;
}
.toggle:checked {
/* @apply: bg-indigo-400; */
background-color: #7f9cf5;
}
.toggle:checked:before {
left: 1.25rem;
}
</style>

View File

@ -4,7 +4,10 @@
</script> </script>
{#if !donor || donor.firstname == 0} {#if !donor || donor.firstname == 0}
{$_("donor-has-no-associated-donations")} <span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current"
>{$_('anonymer_sponsor')}</span
>
{:else} {:else}
<div class="flex items-center"> <div class="flex items-center">
<a <a

View File

@ -41,6 +41,8 @@
"already-paid": "Bereits bezahlt", "already-paid": "Bereits bezahlt",
"amount": "Anzahl", "amount": "Anzahl",
"amount-per-kilometer": "Betrag pro Kilometer", "amount-per-kilometer": "Betrag pro Kilometer",
"anonyme_spende": "Anonyme Spende",
"anonymer_sponsor": "👻 Anonymer Sponsor",
"apartment-suite-etc": "Apartment, Wohnung, etc.", "apartment-suite-etc": "Apartment, Wohnung, etc.",
"api-endpoint": "API-Endpunkt", "api-endpoint": "API-Endpunkt",
"application_name": "Lauf für Kaya! - Admin", "application_name": "Lauf für Kaya! - Admin",
@ -224,6 +226,7 @@
"error_on_login": "😢Fehler beim Login", "error_on_login": "😢Fehler beim Login",
"everything-concerning-your-profile": "Alles zu deinem Profil", "everything-concerning-your-profile": "Alles zu deinem Profil",
"faq": "FAQ", "faq": "FAQ",
"festbetrag": "Festbetrag",
"filename_sponsoringquittungsliste": "SponsoringQuittungsListe", "filename_sponsoringquittungsliste": "SponsoringQuittungsListe",
"filter-by-organization-team": "Filtern nach Organisation / Team", "filter-by-organization-team": "Filtern nach Organisation / Team",
"first-name": "Vorname", "first-name": "Vorname",
@ -418,6 +421,7 @@
"settings": "Einstellungen", "settings": "Einstellungen",
"settings-for-your-profile": "Die Einstellungen deines Accounts", "settings-for-your-profile": "Die Einstellungen deines Accounts",
"something-about-the-group": "Infos zur Gruppe", "something-about-the-group": "Infos zur Gruppe",
"spende_pro_km": "Spende pro km",
"sponsoring-quittungs-liste_herunterladen": "Sponsoring-Quittungs-Liste herunterladen", "sponsoring-quittungs-liste_herunterladen": "Sponsoring-Quittungs-Liste herunterladen",
"sponsorings": "Sponsoringerklaerungen", "sponsorings": "Sponsoringerklaerungen",
"station-deleted": "Scannerstation gelöscht", "station-deleted": "Scannerstation gelöscht",

View File

@ -41,6 +41,8 @@
"already-paid": "Already paid", "already-paid": "Already paid",
"amount": "Amount", "amount": "Amount",
"amount-per-kilometer": "Amount per kilometer", "amount-per-kilometer": "Amount per kilometer",
"anonyme_spende": "Anonymous Donation",
"anonymer_sponsor": "👻 Anonymous Donor",
"apartment-suite-etc": "Apartment, suite, etc.", "apartment-suite-etc": "Apartment, suite, etc.",
"api-endpoint": "API-Endpoint", "api-endpoint": "API-Endpoint",
"application_name": "Lauf für Kaya! - Admin", "application_name": "Lauf für Kaya! - Admin",
@ -224,6 +226,7 @@
"error_on_login": "Error on login", "error_on_login": "Error on login",
"everything-concerning-your-profile": "Everything concerning your profile", "everything-concerning-your-profile": "Everything concerning your profile",
"faq": "FAQ", "faq": "FAQ",
"festbetrag": "Fixed Donation",
"filename_sponsoringquittungsliste": "DonorReceiptList", "filename_sponsoringquittungsliste": "DonorReceiptList",
"filter-by-organization-team": "Filter by Organization/ Team", "filter-by-organization-team": "Filter by Organization/ Team",
"first-name": "First name", "first-name": "First name",
@ -418,6 +421,7 @@
"settings": "Settings", "settings": "Settings",
"settings-for-your-profile": "Settings for your profile", "settings-for-your-profile": "Settings for your profile",
"something-about-the-group": "Something about the group...", "something-about-the-group": "Something about the group...",
"spende_pro_km": "donation per km",
"sponsoring-quittungs-liste_herunterladen": "Download donor receipt list", "sponsoring-quittungs-liste_herunterladen": "Download donor receipt list",
"sponsorings": "Sponsorings", "sponsorings": "Sponsorings",
"station-deleted": "station deleted", "station-deleted": "station deleted",

View File

@ -25,3 +25,9 @@
#html5-qrcode-button-camera-stop { #html5-qrcode-button-camera-stop {
@apply px-2 inline-flex text-lg leading-5 font-semibold rounded-md border border-current bg-red-100 text-red-800 mb-2 cursor-pointer; @apply px-2 inline-flex text-lg leading-5 font-semibold rounded-md border border-current bg-red-100 text-red-800 mb-2 cursor-pointer;
} }
.donation_inactive_tab {
@apply min-w-0 flex-1 bg-white first:border-s-0 border-s border-b-2 border-neutral-200 py-4 px-4 text-neutral-800 hover:text-neutral-700 text-sm font-medium text-center overflow-hidden hover:bg-neutral-200 cursor-pointer focus:z-10 focus:outline-hidden focus:bg-neutral-200 disabled:opacity-50 disabled:pointer-events-none;
}
.donation_active_tab {
@apply min-w-0 flex-1 bg-blue-400 text-white first:border-s-0 border-s border-b-2 border-neutral-200 py-4 px-4 text-sm font-medium text-center overflow-hidden cursor-pointer focus:outline-hidden;
}