Compare commits

..

10 Commits

Author SHA1 Message Date
c78bdfa5e2 chore(release): 1.12.7
All checks were successful
Build release images / build-container (push) Successful in 1m4s
2025-05-01 19:16:26 +02:00
b2ed2afd8a fix(deps): fresh lockfile 2025-05-01 19:16:03 +02:00
00d198895e refactor(store): update refresh interval from 2min to 60min 2025-05-01 19:10:42 +02:00
b5c079da9a chore(release): 1.12.6
Some checks failed
Build release images / build-container (push) Failing after 7s
2025-05-01 19:09:59 +02:00
93422b9779 feat(pdfs): Experimental generation of large runner card files 2025-05-01 19:08:49 +02:00
6dcfd9a4fe chore(release): 1.12.5
Some checks failed
Build release images / build-container (push) Failing after 6s
2025-05-01 16:20:01 +02:00
6d1919974a chore(deps): Bump @odit/lfk-client-js to 1.2.7 2025-05-01 16:18:57 +02:00
f27c716296 feat(runners): Show total donations in runner detail 2025-05-01 16:18:16 +02:00
21395241de fix(locales): Fixed translation 2025-05-01 16:06:18 +02:00
8d2cb13195 fix: Update release script to include --only-version flag 2025-04-28 21:40:28 +02:00
8 changed files with 285 additions and 194 deletions

View File

@@ -2,8 +2,33 @@
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.7](https://git.odit.services/lfk/frontend/compare/1.12.6...1.12.7)
- fix(deps): fresh lockfile [`b2ed2af`](https://git.odit.services/lfk/frontend/commit/b2ed2afd8a45a1a01ac6118b27941e3b4b3b611f)
- refactor(store): update refresh interval from 2min to 60min [`00d1988`](https://git.odit.services/lfk/frontend/commit/00d198895e15174b70a8d229974b4baa7d0ed8fc)
#### [1.12.6](https://git.odit.services/lfk/frontend/compare/1.12.5...1.12.6)
> 1 May 2025
- feat(pdfs): Experimental generation of large runner card files [`93422b9`](https://git.odit.services/lfk/frontend/commit/93422b97799c5e45c89acadd34f33b1a11b04617)
- chore(release): 1.12.6 [`b5c079d`](https://git.odit.services/lfk/frontend/commit/b5c079da9a0545d146e9f3029a543e04c907add3)
#### [1.12.5](https://git.odit.services/lfk/frontend/compare/1.12.4...1.12.5)
> 1 May 2025
- chore(release): 1.12.5 [`6dcfd9a`](https://git.odit.services/lfk/frontend/commit/6dcfd9a4fedd1e44894c9803482576bc650fb4db)
- fix(locales): Fixed translation [`2139524`](https://git.odit.services/lfk/frontend/commit/21395241de4de8f3a6b8404758d09c01d8a6f95f)
- feat(runners): Show total donations in runner detail [`f27c716`](https://git.odit.services/lfk/frontend/commit/f27c716296e228ecccbf500a21130f1bc47ea52d)
- chore(deps): Bump @odit/lfk-client-js to 1.2.7 [`6d19199`](https://git.odit.services/lfk/frontend/commit/6d1919974aacd74a265cf9ce0c9ed501028f0aa3)
- fix: Update release script to include --only-version flag [`8d2cb13`](https://git.odit.services/lfk/frontend/commit/8d2cb13195856f47022d414f3243e9a21457832b)
#### [1.12.4](https://git.odit.services/lfk/frontend/compare/1.12.3...1.12.4) #### [1.12.4](https://git.odit.services/lfk/frontend/compare/1.12.3...1.12.4)
> 28 April 2025
- chore(release): 1.12.4 [`e61e8b0`](https://git.odit.services/lfk/frontend/commit/e61e8b063af75539b7db93c5ca42965417019f29)
- fix: Disable ios auto zooming on inputs [`073c78d`](https://git.odit.services/lfk/frontend/commit/073c78d98afd1c2f08b190aeda942a634e9bb888) - fix: Disable ios auto zooming on inputs [`073c78d`](https://git.odit.services/lfk/frontend/commit/073c78d98afd1c2f08b190aeda942a634e9bb888)
#### [1.12.3](https://git.odit.services/lfk/frontend/compare/1.12.2...1.12.3) #### [1.12.3](https://git.odit.services/lfk/frontend/compare/1.12.2...1.12.3)

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.12.4-RELEASE_INFO</span >RELEASE_INFO-1.12.7-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,13 +1,13 @@
{ {
"name": "@odit/lfk-frontend", "name": "@odit/lfk-frontend",
"version": "1.12.4", "version": "1.12.7",
"type": "module", "type": "module",
"scripts": { "scripts": {
"i18n-order": "node order.js", "i18n-order": "node order.js",
"dev": "vite", "dev": "vite",
"format": "prettier --write --plugin-search-dir=. .", "format": "prettier --write --plugin-search-dir=. .",
"build": "vite build", "build": "vite build",
"release": "release-it", "release": "release-it --only-version",
"licenses:export": "license-exporter --json -o public" "licenses:export": "license-exporter --json -o public"
}, },
"license": "CC-BY-NC-SA-4.0", "license": "CC-BY-NC-SA-4.0",
@@ -43,7 +43,7 @@
"dependencies": { "dependencies": {
"@bwip-js/browser": "^4.6.0", "@bwip-js/browser": "^4.6.0",
"@fontsource/athiti": "^5.2.5", "@fontsource/athiti": "^5.2.5",
"@odit/lfk-client-js": "1.2.5", "@odit/lfk-client-js": "1.2.7",
"@paralleldrive/cuid2": "2.2.2", "@paralleldrive/cuid2": "2.2.2",
"@tailwindcss/vite": "^4.1.4", "@tailwindcss/vite": "^4.1.4",
"@tanstack/svelte-table": "8.9.1", "@tanstack/svelte-table": "8.9.1",

10
pnpm-lock.yaml generated
View File

@@ -15,8 +15,8 @@ importers:
specifier: ^5.2.5 specifier: ^5.2.5
version: 5.2.5 version: 5.2.5
'@odit/lfk-client-js': '@odit/lfk-client-js':
specifier: 1.2.5 specifier: 1.2.7
version: 1.2.5 version: 1.2.7
'@paralleldrive/cuid2': '@paralleldrive/cuid2':
specifier: 2.2.2 specifier: 2.2.2
version: 2.2.2 version: 2.2.2
@@ -491,8 +491,8 @@ packages:
'@octokit/types@13.10.0': '@octokit/types@13.10.0':
resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==} resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==}
'@odit/lfk-client-js@1.2.5': '@odit/lfk-client-js@1.2.7':
resolution: {integrity: sha512-a5vwqpjFXB5cVOCmjC/tZVi9OXJS8aMesNidSqwK2cwA/oC5yTJAqxKXGDhq9k/JLLipVGDJdaKMYmYVzRWkgA==} resolution: {integrity: sha512-sqbbTjGlalN32VPshXClR3qM0+TFgWCX9+2UCo7u/tABEIs7hsYTVXKSZ+fJNfAUCK6ZJiZV0ND6+Dcnk7s29A==}
'@odit/license-exporter@0.2.0': '@odit/license-exporter@0.2.0':
resolution: {integrity: sha512-RRyfQzDLoyLQlGSd8ThJQ3h0fiCe4tkmm935AUvSVQWP+p88FcnI4iaktKBJJVBnIpDhkv/7sDSA5dFc/QMM5w==} resolution: {integrity: sha512-RRyfQzDLoyLQlGSd8ThJQ3h0fiCe4tkmm935AUvSVQWP+p88FcnI4iaktKBJJVBnIpDhkv/7sDSA5dFc/QMM5w==}
@@ -2412,7 +2412,7 @@ snapshots:
dependencies: dependencies:
'@octokit/openapi-types': 24.2.0 '@octokit/openapi-types': 24.2.0
'@odit/lfk-client-js@1.2.5': {} '@odit/lfk-client-js@1.2.7': {}
'@odit/license-exporter@0.2.0': '@odit/license-exporter@0.2.0':
dependencies: dependencies:

View File

@@ -1,197 +1,256 @@
<script> <script>
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { import {
RunnerCardService, RunnerCardService,
RunnerOrganizationService, RunnerOrganizationService,
RunnerTeamService, RunnerTeamService,
} from "@odit/lfk-client-js"; } from "@odit/lfk-client-js";
import toast from "svelte-french-toast"; import toast from "svelte-french-toast";
import DocumentServer from "./DocumentServer.ts"; import DocumentServer from "./DocumentServer.ts";
import { init } from "@paralleldrive/cuid2"; import { init } from "@paralleldrive/cuid2";
const createId = init({ length: 10, fingerprint: "lfk-frontend" }); const createId = init({ length: 10, fingerprint: "lfk-frontend" });
const documentServer = new DocumentServer( const documentServer = new DocumentServer(
config.baseurl_documentserver, config.baseurl_documentserver,
config.documentserver_key config.documentserver_key
); );
export let cards_show = false; export let cards_show = false;
export let generate_cards = []; export let generate_cards = [];
export let generate_runners = []; export let generate_runners = [];
export let generate_orgs = []; export let generate_orgs = [];
export let generate_teams = []; export let generate_teams = [];
function download(blob, fileName) { function download(blob, fileName) {
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
let a = document.createElement("a"); let a = document.createElement("a");
a.href = url; a.href = url;
a.download = fileName; a.download = fileName;
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
a.remove(); a.remove();
toast.dismiss(); toast.dismiss();
toast.success($_("pdf-successfully-generated")); toast.success($_("pdf-successfully-generated"));
} }
function generateRunnerCards(locale) { function generateRunnerCards(locale, useCombined = false) {
if (generate_orgs.length > 0) { if (generate_orgs.length > 0) {
generateOrgCards(locale); if(useCombined){
} else if (generate_teams.length > 0) { generateOrgCardsCombined(locale);
generateTeamCards(locale);
} else if (generate_runners.length > 0) {
generateRunnersCards(locale);
} else { } else {
generateCards(locale); generateOrgCards(locale)
} }
} } else if (generate_teams.length > 0) {
generateTeamCards(locale);
} else if (generate_runners.length > 0) {
generateRunnersCards(locale);
} else {
generateCards(locale);
}
}
function generateCards(locale) { function generateCards(locale) {
toast.loading($_("generating-pdf")); toast.loading($_("generating-pdf"));
documentServer documentServer
.generateCards(generate_cards, locale) .generateCards(generate_cards, locale)
.then((blob) => { .then((blob) => {
download(blob, `${$_("runnercards")}-${locale}-${createId()}.pdf`); download(blob, `${$_("runnercards")}-${locale}-${createId()}.pdf`);
}) })
.catch((err) => { .catch((err) => {
console.error(err); console.error(err);
}); });
} }
async function generateRunnersCards(locale) { async function generateRunnersCards(locale) {
toast.loading($_("generating-pdf")); toast.loading($_("generating-pdf"));
const current_cards = await RunnerCardService.runnerCardControllerGetAll(); const current_cards = await RunnerCardService.runnerCardControllerGetAll();
let cards = []; let cards = [];
for (let runner of generate_runners) { for (let runner of generate_runners) {
let card = current_cards.find((c) => c.runner?.id == runner.id); let card = current_cards.find((c) => c.runner?.id == runner.id);
if (!card) { if (!card) {
card = await RunnerCardService.runnerCardControllerPost({ card = await RunnerCardService.runnerCardControllerPost({
runner: runner.id, runner: runner.id,
}); });
} }
cards.push(card); cards.push(card);
} }
documentServer documentServer
.generateCards(cards, locale) .generateCards(cards, locale)
.then((blob) => { .then((blob) => {
let fileName = `${$_("runnercards")}-${locale}-${createId()}.pdf`; let fileName = `${$_("runnercards")}-${locale}-${createId()}.pdf`;
if (generate_runners.length == 1) { if (generate_runners.length == 1) {
fileName = `${$_("runnercards")}_${generate_runners[0].firstname}_${ fileName = `${$_("runnercards")}_${generate_runners[0].firstname}_${
generate_runners[0].lastname generate_runners[0].lastname
}-${locale}-${createId()}.pdf`; }-${locale}-${createId()}.pdf`;
} }
download(blob, fileName); download(blob, fileName);
}) })
.catch((err) => {}); .catch((err) => {});
} }
async function generateTeamCards(locale) { async function generateTeamCards(locale) {
toast.loading($_("generating-pdfs")); toast.loading($_("generating-pdfs"));
let count = 0; let count = 0;
const current_cards = await RunnerCardService.runnerCardControllerGetAll(); const current_cards = await RunnerCardService.runnerCardControllerGetAll();
for (const t of generate_teams) { for (const t of generate_teams) {
const runners = await RunnerTeamService.runnerTeamControllerGetRunners( const runners = await RunnerTeamService.runnerTeamControllerGetRunners(
t.id t.id
); );
let cards = []; let cards = [];
for (let runner of runners) { for (let runner of runners) {
let card = current_cards.find((c) => c.runner?.id == runner.id); let card = current_cards.find((c) => c.runner?.id == runner.id);
if (!card) { if (!card) {
card = await RunnerCardService.runnerCardControllerPost({ card = await RunnerCardService.runnerCardControllerPost({
runner: runner.id, runner: runner.id,
}); });
} }
cards.push(card); cards.push(card);
} }
documentServer documentServer
.generateCards(cards, locale) .generateCards(cards, locale)
.then((blob) => { .then((blob) => {
download( download(
blob, blob,
`${$_("runnercards")}_${t.name}-${locale}-${createId()}.pdf` `${$_("runnercards")}_${t.name}-${locale}-${createId()}.pdf`
); );
}) })
.catch((err) => {}); .catch((err) => {});
} }
} }
async function generateOrgCards(locale) { async function generateOrgCards(locale) {
toast.loading($_("generating-pdfs")); toast.loading($_("generating-pdfs"));
const current_cards = await RunnerCardService.runnerCardControllerGetAll(); const current_cards = await RunnerCardService.runnerCardControllerGetAll();
let count = 0; let count = 0;
let count_orgs = 0; let count_orgs = 0;
for (const o of generate_orgs) { for (const o of generate_orgs) {
count_orgs++; count_orgs++;
let count = 0; let count = 0;
let runners = let runners =
await RunnerOrganizationService.runnerOrganizationControllerGetRunners( await RunnerOrganizationService.runnerOrganizationControllerGetRunners(
o.id, o.id,
true true
); );
let cards = []; let cards = [];
for (let runner of runners) { for (let runner of runners) {
let card = current_cards.find((c) => c.runner?.id == runner.id); let card = current_cards.find((c) => c.runner?.id == runner.id);
if (!card) { if (!card) {
card = await RunnerCardService.runnerCardControllerPost({ card = await RunnerCardService.runnerCardControllerPost({
runner: runner.id, runner: runner.id,
}); });
} }
cards.push(card); cards.push(card);
} }
await documentServer await documentServer
.generateCards(cards, locale) .generateCards(cards, locale)
.then((blob) => { .then((blob) => {
download( download(
blob, blob,
`${$_("runnercards")}_${o.name}_direct-${locale}-${createId()}.pdf` `${$_("runnercards")}_${o.name}_direct-${locale}-${createId()}.pdf`
); );
}) })
.catch((err) => {}); .catch((err) => {});
for (const t of o.teams) { for (const t of o.teams) {
count++; count++;
let runners = await RunnerTeamService.runnerTeamControllerGetRunners( let runners = await RunnerTeamService.runnerTeamControllerGetRunners(
t.id t.id
); );
let cards = []; let cards = [];
for (let runner of runners) { for (let runner of runners) {
let card = current_cards.find((c) => c.runner?.id == runner.id); let card = current_cards.find((c) => c.runner?.id == runner.id);
if (!card) { if (!card) {
card = await RunnerCardService.runnerCardControllerPost({ card = await RunnerCardService.runnerCardControllerPost({
runner: runner.id, runner: runner.id,
}); });
} }
cards.push(card); cards.push(card);
} }
await documentServer await documentServer
.generateCards(cards, locale) .generateCards(cards, locale)
.then((blob) => { .then((blob) => {
download( download(
blob, blob,
`${$_("runnercards")}_${o.name}_${ `${$_("runnercards")}_${o.name}_${
t.name t.name
}-${locale}-${createId()}.pdf` }-${locale}-${createId()}.pdf`
); );
}) })
.catch((err) => {}); .catch((err) => {});
} }
} }
} }
async function generateOrgCardsCombined(locale) {
toast.loading($_("generating-pdfs"));
const current_cards = await RunnerCardService.runnerCardControllerGetAll();
let count = 0;
let count_orgs = 0;
for (const o of generate_orgs) {
count_orgs++;
let cards = [];
let count = 0;
let runners =
await RunnerOrganizationService.runnerOrganizationControllerGetRunners(
o.id,
true
);
for (let runner of runners) {
let card = current_cards.find((c) => c.runner?.id == runner.id);
if (!card) {
card = await RunnerCardService.runnerCardControllerPost({
runner: runner.id,
});
}
cards.push(card);
}
for (const t of o.teams) {
count++;
let runners = await RunnerTeamService.runnerTeamControllerGetRunners(
t.id
);
for (let runner of runners) {
let card = current_cards.find((c) => c.runner?.id == runner.id);
if (!card) {
card = await RunnerCardService.runnerCardControllerPost({
runner: runner.id,
});
}
cards.push(card);
}
}
await documentServer
.generateCards(cards, locale)
.then((blob) => {
download(
blob,
`${$_("runnercards")}_${o.name}-${locale}-${createId()}.pdf`
);
})
.catch((err) => {});
}
}
</script> </script>
{#if cards_show} {#if cards_show}
<button <button
on:click={() => { on:click={() => {
generateRunnerCards("de"); generateRunnerCards("de");
}} }}
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" on:contextmenu|preventDefault={() => {
> generateRunnerCards("de", true);
{$_("generate-runnercards")}: DE }}
</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:w-auto sm:text-sm mb-1 lg:mb-0"
<button >
on:click={() => { {$_("generate-runnercards")}: DE
generateRunnerCards("en"); </button>
}} <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:w-auto sm:text-sm mb-1 lg:mb-0" on:click={() => {
> generateRunnerCards("en");
{$_("generate-runnercards")}: EN }}
</button> on:contextmenu|preventDefault={() => {
generateRunnerCards("en", true);
}}
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"
>
{$_("generate-runnercards")}: EN
</button>
{/if} {/if}

View File

@@ -289,6 +289,13 @@
<br /> <br />
<span class="text-gray-700">{original_data.distance / 1000} km</span> <span class="text-gray-700">{original_data.distance / 1000} km</span>
</div> </div>
<div class="text-sm w-full mt-2">
<span class="font-semibold text-gray-700">{$_("total-donation-amount")}</span>
<br />
<span class="text-gray-700">{(editable.donationAmount / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })}</span>
</div>
<div class="text-sm w-full mt-2"> <div class="text-sm w-full mt-2">
<span class="font-semibold text-gray-700">{$_("created_via")}</span> <span class="font-semibold text-gray-700">{$_("created_via")}</span>
<br /> <br />

View File

@@ -468,7 +468,7 @@
"timestamp": "timestamp", "timestamp": "timestamp",
"token": "Token", "token": "Token",
"total-distance": "total distance", "total-distance": "total distance",
"total-donation-amount": "total donation amount", "total-donation-amount": "Total donations",
"total-donation-count": "total donations (count)", "total-donation-count": "total donations (count)",
"total-donations": "total donations", "total-donations": "total donations",
"total-donors": "total donors", "total-donors": "total donors",

View File

@@ -43,8 +43,8 @@ const store = () => {
// //
state.refreshInterval = setInterval(() => { state.refreshInterval = setInterval(() => {
this.refreshAuth(); this.refreshAuth();
// 2min // 60min
}, 2 * 60000); }, 60 * 60000);
// //
return state; return state;
}); });