Compare commits

...

33 Commits
main ... 1.2.4

Author SHA1 Message Date
f1d552ce64
🚀Bumped version to v1.2.4 2025-03-17 22:35:58 +01:00
2939911c99
feat: loading screen 2025-03-17 22:35:12 +01:00
e7b9c6e203
🚀Bumped version to v1.2.3 2025-03-17 22:22:39 +01:00
3641d2a783
no selfservice sponsor add for now 2025-03-17 22:21:17 +01:00
ccea9d6197
shareSponsorLink function 2025-03-17 22:20:54 +01:00
c94f9e550e
i18n 2025-03-17 22:15:00 +01:00
0848209d49
feat: disable darkmode for now, also is better for visibility on day of run... 2025-03-17 22:06:51 +01:00
1202f2ebca
feat: profile cleanup 2025-03-17 22:06:32 +01:00
4714b81465
wip 2025-03-17 22:00:31 +01:00
7f2e6b9160
cleanup 2025-03-17 21:54:06 +01:00
0366f95951
feat: cleanup profile 2025-03-17 21:52:44 +01:00
382757aa66
feat: wip: sponsoring add 2025-03-17 21:43:47 +01:00
34e63cf690
feat: improve profile 2025-03-17 21:32:02 +01:00
846d10f0b9
feat: improve profile 2025-03-17 21:29:13 +01:00
86ec22aa43
feat: cleanup profile 2025-03-17 21:16:57 +01:00
f6f46f41bf
feat(footer): 2024 2025-03-17 20:32:32 +01:00
64bb2d157d
chore(deps): bump 2025-03-17 20:32:23 +01:00
c8ceae5cf0
🚀Bumped version to v1.2.2
Some checks failed
ci/woodpecker/push/build Pipeline failed
ci/woodpecker/tag/release Pipeline was successful
2024-12-16 17:10:39 +01:00
1d7cd601ee
feat(profile): add cursor pointer
Some checks failed
ci/woodpecker/push/build Pipeline failed
2024-12-16 17:10:27 +01:00
9ddb188ef6
🚀Bumped version to v1.2.1
All checks were successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/tag/release Pipeline was successful
2024-12-16 17:03:30 +01:00
4996b8c526
Merge branch 'dev' of https://git.odit.services/lfk/selfservice into dev 2024-12-16 17:03:06 +01:00
7d2a29c0d8
🚀Bumped version to v1.2.0
All checks were successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/tag/release Pipeline was successful
2024-12-16 16:56:10 +01:00
721892c315
refacor(documents): Switch to new document-server 2024-12-16 16:55:26 +01:00
d5641312ca
feat(profile): updated tab alignment 2024-12-16 16:55:16 +01:00
c34a8a7fcc
refactor(profile): replace styles with tailwindcss 2024-12-16 16:55:01 +01:00
55abb9ed22
feat(profile): show total distance 2024-12-16 16:54:06 +01:00
1d55445c1b
🚀Bumped version to v1.1.2
Some checks failed
ci/woodpecker/push/build Pipeline failed
ci/woodpecker/tag/release Pipeline was successful
2024-12-11 23:08:38 +01:00
762454a086
fix(profile): migrate to code128 2024-12-11 23:08:27 +01:00
25c2a170bc
chore(deps): bump all 2024-12-11 22:45:30 +01:00
b21ad636ad
refactor: drop postbuild step 2024-12-11 22:45:20 +01:00
4771bf1359
🚀Bumped version to v1.1.1
All checks were successful
ci/woodpecker/tag/release Pipeline was successful
ci/woodpecker/push/build Pipeline was successful
2024-12-11 22:43:36 +01:00
dbe707b062
fix(profile): passed id is a jwt 2024-12-11 22:43:02 +01:00
dee1b7a6ea
🚀Bumped version to v1.1.0
All checks were successful
ci/woodpecker/tag/release Pipeline was successful
ci/woodpecker/push/build Pipeline was successful
2024-12-02 16:50:31 +01:00
12 changed files with 1689 additions and 1602 deletions

View File

@ -2,9 +2,82 @@
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.2.4](https://git.odit.services/lfk/selfservice/compare/1.2.3...1.2.4)
- feat: loading screen [`2939911`](https://git.odit.services/lfk/selfservice/commit/2939911c993c3817d841d4cb4660aa940e478cc0)
#### [1.2.3](https://git.odit.services/lfk/selfservice/compare/1.2.2...1.2.3)
> 17 March 2025
- chore(deps): bump [`64bb2d1`](https://git.odit.services/lfk/selfservice/commit/64bb2d157daab257b6e0e7c4e6ed04f4b3772740)
- feat: cleanup profile [`86ec22a`](https://git.odit.services/lfk/selfservice/commit/86ec22aa435d9138ae3cde6387ce7ead14f3c964)
- feat: improve profile [`846d10f`](https://git.odit.services/lfk/selfservice/commit/846d10f0b95dad460a068bdaf3ca489d96c0b723)
- feat: profile cleanup [`1202f2e`](https://git.odit.services/lfk/selfservice/commit/1202f2ebca5fbc0baea145dda6f99668d8c47e92)
- feat: improve profile [`34e63cf`](https://git.odit.services/lfk/selfservice/commit/34e63cf690431da973a969376b493d8b34f5c7c0)
- i18n [`c94f9e5`](https://git.odit.services/lfk/selfservice/commit/c94f9e550e1cbe4626242423deb6d9ab994eea63)
- feat: wip: sponsoring add [`382757a`](https://git.odit.services/lfk/selfservice/commit/382757aa66cd79a6a8081ff4b21f6efe46a3ccfd)
- feat: cleanup profile [`0366f95`](https://git.odit.services/lfk/selfservice/commit/0366f95951d1415b300b174699d93e4bf17f3e18)
- 🚀Bumped version to v1.2.3 [`e7b9c6e`](https://git.odit.services/lfk/selfservice/commit/e7b9c6e2036addd18e109e3ab040e69dee2f658d)
- shareSponsorLink function [`ccea9d6`](https://git.odit.services/lfk/selfservice/commit/ccea9d61975bfa54928d557735cd3ce79d671435)
- no selfservice sponsor add for now [`3641d2a`](https://git.odit.services/lfk/selfservice/commit/3641d2a78341b91a26a9d4cc31c40707096768b1)
- feat: disable darkmode for now, also is better for visibility on day of run... [`0848209`](https://git.odit.services/lfk/selfservice/commit/0848209d49e4445881bf9536d87fe18ea2a6c924)
- wip [`4714b81`](https://git.odit.services/lfk/selfservice/commit/4714b814650d4138d8522dd57b5ee59a8c96a0ac)
- feat(footer): 2024 [`f6f46f4`](https://git.odit.services/lfk/selfservice/commit/f6f46f41bf2c6fcf75dbd79a28f6dd14114445e3)
- cleanup [`7f2e6b9`](https://git.odit.services/lfk/selfservice/commit/7f2e6b916076874cfb2e787ae174320b50d2d7e0)
#### [1.2.2](https://git.odit.services/lfk/selfservice/compare/1.2.1...1.2.2)
> 16 December 2024
- feat(profile): add cursor pointer [`1d7cd60`](https://git.odit.services/lfk/selfservice/commit/1d7cd601ee027dd7df0405079e208d03078210bb)
- 🚀Bumped version to v1.2.2 [`c8ceae5`](https://git.odit.services/lfk/selfservice/commit/c8ceae5cf016341af1bc903fb219e544bb2f0d58)
#### [1.2.1](https://git.odit.services/lfk/selfservice/compare/1.2.0...1.2.1)
> 16 December 2024
- feat(profile): show total distance [`55abb9e`](https://git.odit.services/lfk/selfservice/commit/55abb9ed22e4c66c05536897ba33b12915eea226)
- refactor(profile): replace styles with tailwindcss [`c34a8a7`](https://git.odit.services/lfk/selfservice/commit/c34a8a7fcc77a0fa27280365ebf2382fbffc1e61)
- 🚀Bumped version to v1.2.1 [`9ddb188`](https://git.odit.services/lfk/selfservice/commit/9ddb188ef659742018f00d786e030f80a0d9bbc5)
- feat(profile): updated tab alignment [`d564131`](https://git.odit.services/lfk/selfservice/commit/d5641312ca0b35a5c5ab9b7b19ed3a40971ac4fd)
#### [1.2.0](https://git.odit.services/lfk/selfservice/compare/1.1.2...1.2.0)
> 16 December 2024
- refacor(documents): Switch to new document-server [`721892c`](https://git.odit.services/lfk/selfservice/commit/721892c315de9c2c1158d0f728dc2ef387a5d8c2)
- 🚀Bumped version to v1.2.0 [`7d2a29c`](https://git.odit.services/lfk/selfservice/commit/7d2a29c0d834fbe783e59308af89bb8fb46a8015)
#### [1.1.2](https://git.odit.services/lfk/selfservice/compare/1.1.1...1.1.2)
> 11 December 2024
- chore(deps): bump all [`25c2a17`](https://git.odit.services/lfk/selfservice/commit/25c2a170bc9cde66498ae3d7f966201f2b28b679)
- 🚀Bumped version to v1.1.2 [`1d55445`](https://git.odit.services/lfk/selfservice/commit/1d55445c1b67ec2e1be73172d8e451f038451f59)
- refactor: drop postbuild step [`b21ad63`](https://git.odit.services/lfk/selfservice/commit/b21ad636ad69886878d5bd0f441f4187e4f22a5c)
- fix(profile): migrate to code128 [`762454a`](https://git.odit.services/lfk/selfservice/commit/762454a08674303881063337ddf86da564b191f1)
#### [1.1.1](https://git.odit.services/lfk/selfservice/compare/1.1.0...1.1.1)
> 11 December 2024
- 🚀Bumped version to v1.1.1 [`4771bf1`](https://git.odit.services/lfk/selfservice/commit/4771bf135986f90f344757083236539b9d590e83)
- fix(profile): passed id is a jwt [`dbe707b`](https://git.odit.services/lfk/selfservice/commit/dbe707b062ced048428b8c1f62a0ab047ab0051b)
#### [1.1.0](https://git.odit.services/lfk/selfservice/compare/1.0.1...1.1.0)
> 2 December 2024
- refactor: drop sub-directory routing [`4bcbc67`](https://git.odit.services/lfk/selfservice/commit/4bcbc67436e6c0b0905e3ef2613894854d659091)
- 🚀Bumped version to v1.1.0 [`dee1b7a`](https://git.odit.services/lfk/selfservice/commit/dee1b7a6eab11689bae8914e74bea7cb364475e2)
#### [1.0.1](https://git.odit.services/lfk/selfservice/compare/1.0.0...1.0.1) #### [1.0.1](https://git.odit.services/lfk/selfservice/compare/1.0.0...1.0.1)
> 2 December 2024
- fix(container): Add dockeringore [`7fcb6a9`](https://git.odit.services/lfk/selfservice/commit/7fcb6a9fc3f98772990790f6385200732f8bce7c) - fix(container): Add dockeringore [`7fcb6a9`](https://git.odit.services/lfk/selfservice/commit/7fcb6a9fc3f98772990790f6385200732f8bce7c)
- 🚀Bumped version to v1.0.1 [`595735a`](https://git.odit.services/lfk/selfservice/commit/595735ad003b849521e6e5f2b24da4880f768dff)
### [1.0.0](https://git.odit.services/lfk/selfservice/compare/0.11.3...1.0.0) ### [1.0.0](https://git.odit.services/lfk/selfservice/compare/0.11.3...1.0.0)

View File

@ -1,4 +1,4 @@
FROM node:23.3.0-alpine3.20 AS build FROM node:23.4.0-alpine3.20 AS build
# FROM registry.odit.services/hub/library/node:23.3.0-alpine3.20 AS build # FROM registry.odit.services/hub/library/node:23.3.0-alpine3.20 AS build
# ARG NPM_REGISTRY_URL=https://registry.npmjs.org # ARG NPM_REGISTRY_URL=https://registry.npmjs.org
WORKDIR /app WORKDIR /app
@ -7,7 +7,6 @@ COPY . .
RUN npm i -g pnpm@9 RUN npm i -g pnpm@9
RUN pnpm i --frozen-lockfile RUN pnpm i --frozen-lockfile
RUN pnpm build RUN pnpm build
RUN pnpm postbuild
# final image # final image
FROM registry.odit.services/library/nginx-brotli:3.15 AS final FROM registry.odit.services/library/nginx-brotli:3.15 AS final

View File

@ -1,6 +0,0 @@
import { existsSync, writeFileSync, readFileSync } from "node:fs";
if (existsSync("./dist/index.html")) {
const content = readFileSync("./dist/index.html", { encoding: "utf8" });
const newcontent = content.replace(`"/env.js"`, `"./env.js"`);
writeFileSync("./dist/index.html", newcontent);
}

View File

@ -1,20 +1,19 @@
{ {
"name": "@odit/lfk-selfservice", "name": "@odit/lfk-selfservice",
"version": "1.0.1", "version": "1.2.4",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"release": "release-it", "release": "release-it"
"postbuild": "node env_fix.js"
}, },
"dependencies": { "dependencies": {
"@fontsource/athiti": "^5.1.0", "@fontsource/athiti": "5.2.5",
"@tailwindcss/vite": "4.0.0-beta.4", "@tailwindcss/vite": "4.0.14",
"bwip-js": "4.5.1", "bwip-js": "4.5.2",
"marked": "15.0.3", "marked": "15.0.7",
"redaxios": "0.5.1", "redaxios": "0.5.1",
"tailwindcss": "4.0.0-beta.4", "tailwindcss": "4.0.14",
"toastify-js": "1.12.0", "toastify-js": "1.12.0",
"validator": "13.12.0", "validator": "13.12.0",
"vue": "3.5.13", "vue": "3.5.13",
@ -23,11 +22,11 @@
"vue-toastification": "2.0.0-rc.1" "vue-toastification": "2.0.0-rc.1"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "5.2.1", "@vitejs/plugin-vue": "5.2.3",
"autoprefixer": "10.4.20", "autoprefixer": "10.4.21",
"release-it": "17.10.0", "release-it": "18.1.2",
"vite": "6.0.2", "vite": "6.2.2",
"vite-plugin-vue-devtools": "^7.6.7" "vite-plugin-vue-devtools": "7.7.2"
}, },
"release-it": { "release-it": {
"git": { "git": {

2327
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@ const config = {
// required, with trailing slash // required, with trailing slash
baseurl: '', baseurl: '',
// full url (including fqdn) // full url (including fqdn)
baseurl_documentserver: 'http://localhost:4010/documents', baseurl_documentserver: 'http://localhost:3000',
// optional, will fallback to code128 // optional, will fallback to code128
code_format: 'ean13', code_format: 'ean13',
// optional, will fallback to /imprint // optional, will fallback to /imprint

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -1,15 +1,15 @@
<template> <template>
<footer> <footer>
<div class="container px-5 py-8 mx-auto flex items-center sm:flex-row flex-col"> <div class="container px-5 py-8 mx-auto flex items-center sm:flex-row flex-col">
<p class="text-sm text-gray-400 sm:ml-4 sm:pl-4 sm:py-2 sm:mt-0 mt-4 text-center md:text-left"> <p class="text-sm sm:ml-4 sm:pl-4 sm:py-2 sm:mt-0 mt-4 text-center md:text-left">
Lauf für Kaya! Selfservice<br>Copyright © 2024<br>proudly powered by Lauf für Kaya! Selfservice<br>Copyright © 2025<br>proudly powered by
<a class="underline" target="_blank" rel="noopener,noreferrer" <a class="underline" target="_blank" rel="noopener,noreferrer"
href="https://odit.services?ref=lfk">ODIT.Services</a> href="https://odit.services?ref=lfk">ODIT.Services</a>
</p> </p>
<span class="inline-flex sm:ml-auto sm:mt-0 mt-4 justify-center sm:justify-start"> <span class="inline-flex sm:ml-auto sm:mt-0 mt-4 justify-center sm:justify-start">
<a target="_blank" rel="noopener,noreferrer" :href="[[imprint_url]]" class="ml-3 text-gray-400 underline">{{ <a target="_blank" rel="noopener,noreferrer" :href="[[imprint_url]]" class="ml-3 underline">{{
$t('imprint') }}</a> $t('imprint') }}</a>
<a target="_blank" rel="noopener,noreferrer" :href="[[privacy_url]]" class="ml-3 text-gray-400 underline">{{ <a target="_blank" rel="noopener,noreferrer" :href="[[privacy_url]]" class="ml-3 underline">{{
$t('privacy_policy') }}</a> $t('privacy_policy') }}</a>
</span> </span>
</div> </div>

View File

@ -1,5 +1,6 @@
{ {
"access_is_only_provided_via_your_email_link": "Der Zugang erfolgt über den Link, den Sie bei der Registrierung erhalten haben.", "access_is_only_provided_via_your_email_link": "Der Zugang erfolgt über den Link, den Sie bei der Registrierung erhalten haben.",
"add_sponsoring": "Sponsoring hinzufügen",
"alle_daten_geloescht": "Alle Daten gelöscht!", "alle_daten_geloescht": "Alle Daten gelöscht!",
"already_registered": "bereits registriert...", "already_registered": "bereits registriert...",
"amount_per_kilometer_in_eur": "Betrag pro Kilometer (in €)", "amount_per_kilometer_in_eur": "Betrag pro Kilometer (in €)",
@ -15,9 +16,11 @@
"download_certificate": "Urkunde herunterladen", "download_certificate": "Urkunde herunterladen",
"download_registrationcode": "Registrierungscode herunterladen", "download_registrationcode": "Registrierungscode herunterladen",
"e_mail_adress": "E-Mail Adresse", "e_mail_adress": "E-Mail Adresse",
"e_mail_des_sponsors": "E-Mail des Sponsors",
"error-loading-privacy-policy": "Fehler beim Laden der Datenschutzerklärung", "error-loading-privacy-policy": "Fehler beim Laden der Datenschutzerklärung",
"error_loading_imprint": "Fehler beim Laden des Impressums", "error_loading_imprint": "Fehler beim Laden des Impressums",
"error_requesting_the_login_link": "Fehler beim Anfordern des Login-Links...", "error_requesting_the_login_link": "Fehler beim Anfordern des Login-Links...",
"first_lap": "👏 erste Runde",
"i_accept": "Ich habe die ", "i_accept": "Ich habe die ",
"i_accept_end": "gelesen und akzeptiert.", "i_accept_end": "gelesen und akzeptiert.",
"if_you_are_the_system_administrator_please_refer_to_the_official_product_documentation_readme_for_configuration_guidance": "Wenn Sie der Systemadministrator sind, finden Sie Konfigurationsanweisungen in der offiziellen Produktdokumentation / README.", "if_you_are_the_system_administrator_please_refer_to_the_official_product_documentation_readme_for_configuration_guidance": "Wenn Sie der Systemadministrator sind, finden Sie Konfigurationsanweisungen in der offiziellen Produktdokumentation / README.",
@ -31,7 +34,8 @@
"main_page_text": "Hier können Sie sich für den Lauf Für Kaya! registrieren oder ihr Läuferprofil verwalten.", "main_page_text": "Hier können Sie sich für den Lauf Für Kaya! registrieren oder ihr Läuferprofil verwalten.",
"mittelname": "Mittelname", "mittelname": "Mittelname",
"nachname": "Nachname", "nachname": "Nachname",
"no_laps_scans_were_recorded_yet": "Es wurden noch keine Runden / Scans aufgezeichnet ...", "nachname_des_sponsors": "Nachname des Sponsors",
"no_laps_scans_were_recorded_yet": "Noch keine Runden aufgezeichnet ...",
"no_sponsorings_for_you_were_recorded_yet": "Es gibt noch keine Sponsorings für dich", "no_sponsorings_for_you_were_recorded_yet": "Es gibt noch keine Sponsorings für dich",
"not_registered_yet": "Noch nicht registriert?", "not_registered_yet": "Noch nicht registriert?",
"organization": "Organisation", "organization": "Organisation",
@ -58,14 +62,20 @@
"registrierungscode_generiert": "Registrierungscode generiert!", "registrierungscode_generiert": "Registrierungscode generiert!",
"registrierungscode_wird_generiert": "Registrierungscode wird generiert...", "registrierungscode_wird_generiert": "Registrierungscode wird generiert...",
"resend_the_registration_mail": "Login-Link anfordern", "resend_the_registration_mail": "Login-Link anfordern",
"sponsor_add_agree": "Mit dem Absenden bestätige ich, dass der Sponsor mit der Übermittlung seiner Daten einverstanden ist und ich dessen Berechtigung habe",
"sponsoring": "Sponsoring", "sponsoring": "Sponsoring",
"sponsoring_pro_kilometer_in_eur": "Sponsoring pro Kilometer (in €)",
"strasse": "Straße", "strasse": "Straße",
"telefonnummer_des_sponsors": "Telefonnummer des Sponsors",
"the_system_is_not_properly_configured_please_contact_the_system_administrator_for_help": "Das System ist nicht richtig konfiguriert. Bitte wenden Sie sich an den Systemadministrator, um Hilfe zu erhalten.", "the_system_is_not_properly_configured_please_contact_the_system_administrator_for_help": "Das System ist nicht richtig konfiguriert. Bitte wenden Sie sich an den Systemadministrator, um Hilfe zu erhalten.",
"this_is_not_a_valid_international_phone_number": "Dies ist keine gültige internationale Telefonnummer", "this_is_not_a_valid_international_phone_number": "Dies ist keine gültige internationale Telefonnummer",
"total": "Gesamt", "total": "Gesamt",
"total_distance": "Gesamt-Distanz",
"urkunde_generiert": "Urkunde generiert!", "urkunde_generiert": "Urkunde generiert!",
"urkunde_konnte_nicht_generiert_werden": "Urkunde konnte nicht generiert werden...", "urkunde_konnte_nicht_generiert_werden": "Urkunde konnte nicht generiert werden...",
"urkunde_wird_generiert": "Urkunde wird generiert...", "urkunde_wird_generiert": "Urkunde wird generiert...",
"view_my_data": "Meine Läuferdaten einsehen", "view_my_data": "Meine Läuferdaten einsehen",
"vorname": "Vorname" "vorname": "Vorname",
"vorname_des_sponsors": "Vorname des Sponsors",
"z_b_1eur_oder_0_50eur": "z.B. 1€ ODER 0,50€"
} }

View File

@ -1,5 +1,6 @@
{ {
"access_is_only_provided_via_your_email_link": "Access is only provided via the link you received upon registration.", "access_is_only_provided_via_your_email_link": "Access is only provided via the link you received upon registration.",
"add_sponsoring": "New Sponsoring",
"alle_daten_geloescht": "all data deleted!", "alle_daten_geloescht": "all data deleted!",
"already_registered": "already registered...", "already_registered": "already registered...",
"amount_per_kilometer_in_eur": "Amount per kilometer (in €)", "amount_per_kilometer_in_eur": "Amount per kilometer (in €)",
@ -15,9 +16,11 @@
"download_certificate": "Download certificate", "download_certificate": "Download certificate",
"download_registrationcode": "Download registrationcode", "download_registrationcode": "Download registrationcode",
"e_mail_adress": "mail address", "e_mail_adress": "mail address",
"e_mail_des_sponsors": "E-Mail of the Sponsor",
"error-loading-privacy-policy": "Error loading Privacy Policy", "error-loading-privacy-policy": "Error loading Privacy Policy",
"error_loading_imprint": "Error loading Imprint", "error_loading_imprint": "Error loading Imprint",
"error_requesting_the_login_link": "Error requesting the login link...", "error_requesting_the_login_link": "Error requesting the login link...",
"first_lap": "👏 first lap",
"i_accept": "I have read and accepted the ", "i_accept": "I have read and accepted the ",
"i_accept_end": "", "i_accept_end": "",
"if_you_are_the_system_administrator_please_refer_to_the_official_product_documentation_readme_for_configuration_guidance": "If you are the system administrator, please refer to the official product documentation/ README for configuration guidance.", "if_you_are_the_system_administrator_please_refer_to_the_official_product_documentation_readme_for_configuration_guidance": "If you are the system administrator, please refer to the official product documentation/ README for configuration guidance.",
@ -31,6 +34,7 @@
"main_page_text": "Here you can register for the Lauf Für Kaya! or manage your runner profile.", "main_page_text": "Here you can register for the Lauf Für Kaya! or manage your runner profile.",
"mittelname": "Middlename", "mittelname": "Middlename",
"nachname": "Lastname", "nachname": "Lastname",
"nachname_des_sponsors": "last name of the sponsor",
"no_laps_scans_were_recorded_yet": "No laps/ scans were recorded yet...", "no_laps_scans_were_recorded_yet": "No laps/ scans were recorded yet...",
"no_sponsorings_for_you_were_recorded_yet": "No sponsorings for you were recorded yet...", "no_sponsorings_for_you_were_recorded_yet": "No sponsorings for you were recorded yet...",
"not_registered_yet": "Not registered yet?", "not_registered_yet": "Not registered yet?",
@ -58,14 +62,20 @@
"registrierungscode_generiert": "created registration code!", "registrierungscode_generiert": "created registration code!",
"registrierungscode_wird_generiert": "creating registration code...", "registrierungscode_wird_generiert": "creating registration code...",
"resend_the_registration_mail": "Send me a login link", "resend_the_registration_mail": "Send me a login link",
"sponsor_add_agree": "By submitting, I confirm that the sponsor agrees to the transmission of his data and that I have his authorization",
"sponsoring": "Sponsoring", "sponsoring": "Sponsoring",
"sponsoring_pro_kilometer_in_eur": "Sponsoring per Kilometer (in €)",
"strasse": "Street/ Block", "strasse": "Street/ Block",
"telefonnummer_des_sponsors": "Sponsor's phone number",
"the_system_is_not_properly_configured_please_contact_the_system_administrator_for_help": "The system is not properly configured. Please contact the system administrator for help.", "the_system_is_not_properly_configured_please_contact_the_system_administrator_for_help": "The system is not properly configured. Please contact the system administrator for help.",
"this_is_not_a_valid_international_phone_number": "This is not a valid international phone number", "this_is_not_a_valid_international_phone_number": "This is not a valid international phone number",
"total": "Total", "total": "Total",
"total_distance": "total distance",
"urkunde_generiert": "created certificate", "urkunde_generiert": "created certificate",
"urkunde_konnte_nicht_generiert_werden": "could not create your certificate...", "urkunde_konnte_nicht_generiert_werden": "could not create your certificate...",
"urkunde_wird_generiert": "creating certificate...", "urkunde_wird_generiert": "creating certificate...",
"view_my_data": "View my data", "view_my_data": "View my data",
"vorname": "Firstname" "vorname": "Firstname",
"vorname_des_sponsors": "Sponsor's first name",
"z_b_1eur_oder_0_50eur": "e.g. €1 OR €0.50"
} }

View File

@ -1 +1,8 @@
@import "tailwindcss"; @import "tailwindcss";
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
* {
font-family: Athiti;
}

View File

@ -1,52 +1,73 @@
<template> <template>
<div class="min-h-screen w-full p-4"> <div class="min-h-screen w-full p-4">
<section class="text-white body-font"> <div class="">
<div class="container mx-auto flex items-center md:flex-row flex-col"> <div class="
<div class="
flex flex-col
md:pr-10 md:mb-0 md:pr-10 md:mb-0
mb-6 mb-6
pr-0 pr-0
w-full w-full
md:w-auto md:text-left text-center
text-center text-black text-black
dark:text-gray-200 dark:text-gray-200
"> ">
<p class="text-4xl md:text-3xl font-bold whitespace-nowrap font-[Athiti]" v-text="(state.firstname || '') + <img src="/favicon-lfk.png" class="h-20 mx-auto" />
<div v-if="loadstate === 'loaded'">
<h1 class="text-3xl font-bold whitespace-nowrap font-[Athiti]" v-text="(state.firstname || '') +
' ' + ' ' +
(state.middlename || '') + (state.middlename || '') +
' ' + ' ' +
(state.lastname || '') (state.lastname || '')
"></p> "></h1>
<p class="text-md whitespace-nowrap">{{ state.group }}</p> <p class="text-md whitespace-nowrap">Team: {{ state.group }}</p>
</div> </div>
<div class="inline-flex md:ml-auto md:mr-0 mx-auto items-center"> <h1 v-else class="text-3xl font-bold whitespace-nowrap font-[Athiti]">Daten werden geladen...</h1>
<div v-if="state.delete_active === false"> </div>
<button type="button" class=" <div v-if="loadstate === 'loaded'" class="flex flex-wrap">
focus:border-black focus:ring-2 focus:ring-black <div class="w-full">
text-white text-base md:text-sm <div class="flex flex-wrap flex-col w-full tabs">
py-3.5 <div class="flex lg:flex-wrap flex-row lg:space-x-2 justify-center">
px-5 <div class="flex-none">
md:py-2.5 <button @click="() => {
md:px-5 state.activetab = 'profile';
rounded-md }
bg-blue-500 " :class="{
hover:bg-blue-600 hover:shadow-lg 'tab-active border-b-2 font-medium border-blue-500':
w-full state.activetab === 'profile',
md:w-auto }" class="tab tab-underline cursor-pointer py-4 px-6 block" type="button">
mb-1 {{ $t("profile") }}
md:mr-1 </button>
" @click="get_registration"> </div>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" <div class="flex-none">
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" <button @click="() => {
class="feather feather-download" style="display: inline; height: 1rem; vertical-align: sub"> state.activetab = 'laptimes';
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> }
<polyline points="7 10 12 15 17 10" /> " :class="{
<line x1="12" y1="15" x2="12" y2="3" /> 'tab-active border-b-2 font-medium border-blue-500':
</svg> state.activetab === 'laptimes',
{{ $t("download_registrationcode") }} }" class="tab tab-underline cursor-pointer py-4 px-6 block" type="button">
</button> {{ $t("lap_times") }}
<button type="button" class=" </button>
</div>
<div class="flex-none">
<button @click="() => {
state.activetab = 'sponsorings';
}
" :class="{
'tab-active border-b-2 font-medium border-blue-500':
state.activetab === 'sponsorings',
}" class="tab tab-underline cursor-pointer py-4 px-6 block" type="button">
{{ $t("sponsoring") }}
</button>
</div>
</div>
<div v-if="state.activetab === 'profile'" class="tab-content block container">
<div class="lg:w-2/3 w-full mx-auto">
<div class="flex flex-col container">
<div class="flex flex-wrap w-full">
<div class="w-full">
<div v-if="state.delete_active === false">
<button type="button" class="
mt-2
focus:border-black focus:ring-2 focus:ring-black focus:border-black focus:ring-2 focus:ring-black
text-white text-base md:text-sm text-white text-base md:text-sm
py-3.5 py-3.5
@ -58,19 +79,25 @@
hover:bg-blue-600 hover:shadow-lg hover:bg-blue-600 hover:shadow-lg
w-full w-full
md:w-auto md:w-auto
cursor-pointer
mb-1 mb-1
md:mr-1 md:mr-1
" @click="get_certificate"> " @click="get_certificate">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="feather feather-download" style="display: inline; height: 1rem; vertical-align: sub"> class="inline h-4 align-sub">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="7 10 12 15 17 10" /> <polyline points="7 10 12 15 17 10" />
<line x1="12" y1="15" x2="12" y2="3" /> <line x1="12" y1="15" x2="12" y2="3" />
</svg> </svg>
{{ $t("download_certificate") }} {{ $t("download_certificate") }}
</button> </button>
<button type="button" class="
</div>
<div>
<div class="text-lg">{{ $t("registrationcode") }}</div>
<img class="w-full md:w-auto mb-2 bg-white p-2" alt="Registrierungscode" :src="state.barcode" />
<button type="button" class="
focus:border-black focus:ring-2 focus:ring-black focus:border-black focus:ring-2 focus:ring-black
text-white text-base md:text-sm text-white text-base md:text-sm
py-3.5 py-3.5
@ -78,26 +105,37 @@
md:py-2.5 md:py-2.5
md:px-5 md:px-5
rounded-md rounded-md
bg-red-600 bg-blue-500
hover:bg-red-700 hover:shadow-lg hover:bg-blue-600 hover:shadow-lg
w-full w-full
md:w-auto md:w-auto
" @click="() => { cursor-pointer
state.delete_active = true; mb-1
} md:mr-1
"> " @click="get_registration">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="feather feather-download" style="display: inline; height: 1rem; vertical-align: sub"> class="inline h-4 align-sub">
<path d="M0 0h24v24H0z" /> <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<path fill="currentColor" <polyline points="7 10 12 15 17 10" />
d="M17 6h5v2h-2v13a1 1 0 01-1 1H5a1 1 0 01-1-1V8H2V6h5V3a1 1 0 011-1h8a1 1 0 011 1v3zm1 2H6v12h12V8zm-5 6l2 2-1 1-2-2-2 2-1-1 2-2-2-2 1-1 2 2 2-2 1 1-2 2zM9 4v2h6V4H9z" /> <line x1="12" y1="15" x2="12" y2="3" />
</svg> </svg>
{{ $t("delete_my_data") }} {{ $t("download_registrationcode") }}
</button> </button>
</div> </div>
<div v-if="state.delete_active === true"> <div class="mb-2">
<button type="button" class=" <div class="text-lg">{{ $t("e_mail_adress") }}</div>
<p v-text="state.email || '---'" />
</div>
<div class="mb-2">
<div class="text-lg">{{ $t("phone_number") }}</div>
<p v-text="state.phone || '---'" />
</div>
</div>
</div>
</div>
<div v-if="state.delete_active === true">
<button type="button" class="
focus:border-black focus:ring-2 focus:ring-black focus:border-black focus:ring-2 focus:ring-black
text-white text-base md:text-sm text-white text-base md:text-sm
py-3.5 py-3.5
@ -109,21 +147,22 @@
md:mb-auto md:mb-auto
w-full w-full
md:w-auto md:w-auto
cursor-pointer
bg-blue-500 bg-blue-500
hover:bg-blue-600 hover:shadow-lg hover:bg-blue-600 hover:shadow-lg
" @click="() => { " @click="() => {
state.delete_active = false; state.delete_active = false;
} }
"> ">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="feather feather-download" style="display: inline; height: 1rem; vertical-align: sub"> class="inline h-4 align-sub">
<path fill="none" d="M0 0h24v24H0z" /> <path fill="none" d="M0 0h24v24H0z" />
<path fill="currentColor" d="M12 11l5-5 1 1-5 5 5 5-1 1-5-5-5 5-1-1 5-5-5-5 1-1z" /> <path fill="currentColor" d="M12 11l5-5 1 1-5 5 5 5-1 1-5-5-5 5-1-1 5-5-5-5 1-1z" />
</svg> </svg>
{{ $t("cancel_keep_my_data") }} {{ $t("cancel_keep_my_data") }}
</button> </button>
<button type="button" class=" <button type="button" class="
focus:border-black focus:ring-2 focus:ring-black focus:border-black focus:ring-2 focus:ring-black
text-white text-base md:text-sm text-white text-base md:text-sm
py-3.5 py-3.5
@ -133,211 +172,99 @@
rounded-md rounded-md
w-full w-full
md:w-auto md:w-auto
cursor-pointer
bg-red-600 bg-red-600
hover:bg-red-700 hover:shadow-lg hover:bg-red-700 hover:shadow-lg
md:ml-1 md:ml-1
" @click="delete_me"> " @click="delete_me">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="feather feather-download" style="display: inline; height: 1rem; vertical-align: sub"> class="inline h-4 align-sub">
<path d="M0 0h24v24H0z" /> <path d="M0 0h24v24H0z" />
<path fill="currentColor" <path fill="currentColor"
d="M17 6h5v2h-2v13a1 1 0 01-1 1H5a1 1 0 01-1-1V8H2V6h5V3a1 1 0 011-1h8a1 1 0 011 1v3zm1 2H6v12h12V8zm-5 6l2 2-1 1-2-2-2 2-1-1 2-2-2-2 1-1 2 2 2-2 1 1-2 2zM9 4v2h6V4H9z" /> d="M17 6h5v2h-2v13a1 1 0 01-1 1H5a1 1 0 01-1-1V8H2V6h5V3a1 1 0 011-1h8a1 1 0 011 1v3zm1 2H6v12h12V8zm-5 6l2 2-1 1-2-2-2 2-1-1 2-2-2-2 1-1 2 2 2-2 1 1-2 2zM9 4v2h6V4H9z" />
</svg> </svg>
{{ $t("confirm_delete_all_of_my_data") }} {{ $t("confirm_delete_all_of_my_data") }}
</button> </button>
</div> </div>
</div> <button v-else type="button" class="
</div> focus:border-black focus:ring-2 focus:ring-black
</section> text-white text-base md:text-sm
<div class="flex flex-wrap"> py-3.5
<div class="w-full"> px-5
<div class="flex flex-wrap flex-col w-full tabs"> md:py-2.5
<div class="flex lg:flex-wrap flex-row lg:space-x-2"> md:px-5
<div class="flex-none"> rounded-md
<button @click="() => { bg-red-600
state.activetab = 'profile'; hover:bg-red-700 hover:shadow-lg
w-full
md:w-auto
cursor-pointer
" @click="() => {
state.delete_active = true;
} }
" :class="{ ">
'tab-active border-b-2 font-medium border-blue-500': <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
state.activetab === 'profile', stroke="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
}" class="tab tab-underline py-4 px-6 block" type="button"> class="inline h-4 align-sub">
{{ $t("profile") }} <path d="M0 0h24v24H0z" />
</button> <path fill="currentColor"
</div> d="M17 6h5v2h-2v13a1 1 0 01-1 1H5a1 1 0 01-1-1V8H2V6h5V3a1 1 0 011-1h8a1 1 0 011 1v3zm1 2H6v12h12V8zm-5 6l2 2-1 1-2-2-2 2-1-1 2-2-2-2 1-1 2 2 2-2 1 1-2 2zM9 4v2h6V4H9z" />
<div class="flex-none"> </svg>
<button @click="() => { {{ $t("delete_my_data") }}
state.activetab = 'laptimes'; </button>
}
" :class="{
'tab-active border-b-2 font-medium border-blue-500':
state.activetab === 'laptimes',
}" class="tab tab-underline py-4 px-6 block" type="button">
{{ $t("lap_times") }}
</button>
</div>
<div class="flex-none">
<button @click="() => {
state.activetab = 'sponsorings';
}
" :class="{
'tab-active border-b-2 font-medium border-blue-500':
state.activetab === 'sponsorings',
}" class="tab tab-underline py-4 px-6 block" type="button">
{{ $t("sponsoring") }}
</button>
</div>
</div>
<div v-if="state.activetab === 'profile'" class="tab-content block">
<div class="py-4 w-full">
<div class="flex flex-col">
<form class="form flex flex-wrap w-full">
<div class="w-full">
<div class="form-element">
<div class="text-lg">{{ $t("registrationcode") }}</div>
<img class="w-full md:w-auto mb-2 bg-white p-2" alt="Registrierungscode" :src="state.barcode" />
<div class="text-lg">{{ $t("vorname") }}</div>
<p class="
h-10
w-full
dark:bg-gray-800
rounded
text-base
outline-none
dark:text-gray-100
text-gray-600
py-1
px-3
leading-8
transition-colors
duration-200
ease-in-out
" v-text="state.firstname || '---'" />
</div>
<div class="form-element">
<div class="text-lg">{{ $t("mittelname") }}</div>
<p class="
h-10
w-full
dark:bg-gray-800
rounded
text-base
outline-none
dark:text-gray-100
text-gray-600
py-1
px-3
leading-8
transition-colors
duration-200
ease-in-out
" v-text="state.middlename || '---'" />
</div>
<div class="form-element">
<div class="text-lg">{{ $t("nachname") }}</div>
<p class="
h-10
w-full
dark:bg-gray-800
rounded
text-base
outline-none
dark:text-gray-100
text-gray-600
py-1
px-3
leading-8
transition-colors
duration-200
ease-in-out
" v-text="state.lastname || '---'" />
</div>
<div class="form-element">
<div class="text-lg">{{ $t("e_mail_adress") }}</div>
<p class="
h-10
w-full
dark:bg-gray-800
rounded
text-base
outline-none
dark:text-gray-100
text-gray-600
py-1
px-3
leading-8
transition-colors
duration-200
ease-in-out
" v-text="state.email || '---'" />
</div>
<div class="form-element">
<div class="text-lg">{{ $t("phone_number") }}</div>
<p class="
h-10
w-full
dark:bg-gray-800
rounded
text-base
outline-none
dark:text-gray-100
text-gray-600
py-1
px-3
leading-8
transition-colors
duration-200
ease-in-out
" v-text="state.phone || '---'" />
</div>
</div>
</form>
</div> </div>
</div> </div>
</div> </div>
<div v-if="state.activetab === 'laptimes'" class="tab-content block"> <div v-if="state.activetab === 'laptimes'" class="tab-content block">
<div class="py-4 w-full"> <div class="py-4 w-full">
<section class="text-gray-400 dark:bg-gray-900 body-font"> <section class="dark:bg-gray-900 body-font">
<div class="container mx-auto"> <div class="container mx-auto">
<div class="lg:w-2/3 w-full mx-auto overflow-auto"> <div class="lg:w-2/3 w-full mx-auto">
<table v-if="state.scans.length > 0" class="table-auto w-full text-left whitespace-no-wrap"> <div v-if="state.scans.length > 0">
<thead class=" <p class="mb-2">
{{ $t('total_distance') }}: {{ getReadableDistanceForUI() }}
</p>
<table class="table-auto w-full text-left whitespace-no-wrap">
<thead class="
text-black text-black
bg-gray-300 bg-gray-300
dark:text-white dark:text-white
text-sm text-sm
dark:bg-gray-800 dark:bg-gray-800
"> ">
<tr> <tr>
<th class=" <th class="
px-4 px-4
py-3 py-3
title-font title-font
tracking-wider tracking-wider
font-medium font-medium
"> ">
{{ $t("distance") }} {{ $t("distance") }}
</th> </th>
<th class=" <th class="
px-4 px-4
py-3 py-3
title-font title-font
tracking-wider tracking-wider
font-medium font-medium
"> ">
{{ $t("lap_time") }} {{ $t("lap_time") }}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody class="text-gray-900 dark:text-gray-50"> <tbody class="text-gray-900 dark:text-gray-50">
<tr v-for="s in state.scans" :key="s.id"> <tr v-for="s in state.scans" :key="s.id">
<td class="px-4 py-3"> <td class="px-4 py-3">
<span v-text="s.distance"></span> <span v-text="s.distance_readable"></span>
</td> </td>
<td class="px-4 py-3" v-text="s.lapTime"></td> <td class="px-4 py-3" v-text="s.lapTime_readable"></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div>
<div v-else class=" <div v-else class="
text-center text-center
font-bold font-bold
@ -345,7 +272,7 @@
dark:text-white dark:text-white
text-2xl text-2xl
"> ">
<img src="../assets/empty_laps.svg" style="height: 25rem; margin: 0 auto" <img src="../assets/empty_laps.svg" class="mx-auto h-64"
:alt="[[$t('no_laps_scans_were_recorded_yet')]]" /> :alt="[[$t('no_laps_scans_were_recorded_yet')]]" />
{{ $t("no_laps_scans_were_recorded_yet") }} {{ $t("no_laps_scans_were_recorded_yet") }}
</div> </div>
@ -355,120 +282,203 @@
</div> </div>
</div> </div>
<div v-if="state.activetab === 'sponsorings'" class="tab-content block"> <div v-if="state.activetab === 'sponsorings'" class="tab-content block">
<div class="py-4 w-full"> <div v-if="mode === 'add_sponsoring'">
<section class="text-gray-400 dark:bg-gray-900 body-font"> <h1 class="text-3xl">{{ $t('add_sponsoring') }}</h1>
<div class="container mx-auto"> <form>
<div class="lg:w-2/3 w-full mx-auto overflow-auto"> <div class="mt-6 grid gap-4 lg:gap-6">
<table v-if="state.sponsorings.length > 0" class="table-auto w-full text-left whitespace-no-wrap"> <!-- Grid -->
<thead class=" <div class="grid grid-cols-1 sm:grid-cols-2 gap-4 lg:gap-6">
text-black <div>
bg-gray-300 <label for="sponsorvorname"
class="block mb-2 text-sm text-gray-700 font-medium dark:text-white">{{
$t('vorname_des_sponsors') }}</label>
<input v-bind="newsponsor_vorname" type="text" name="sponsorvorname" id="sponsorvorname"
placeholder="Vorname des Sponsors"
class="py-2.5 sm:py-3 px-4 block w-full border-gray-200 rounded-lg border sm:text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600">
</div>
<div>
<label for="sponsornachname"
class="block mb-2 text-sm text-gray-700 font-medium dark:text-white">{{
$t('nachname_des_sponsors') }}</label>
<input v-bind="newsponsor_nachname" type="text" name="sponsornachname" id="sponsornachname"
placeholder="Nachname des Sponsors"
class="py-2.5 sm:py-3 px-4 block w-full border-gray-200 rounded-lg border sm:text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600">
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 lg:gap-6">
<!-- End Grid -->
<div>
<label for="sponsortel" class="block mb-2 text-sm text-gray-700 font-medium dark:text-white">{{
$t('telefonnummer_des_sponsors') }}</label>
<input v-bind="newsponsor_tel" type="tel" name="sponsortel" id="sponsortel" autocomplete="tel"
class="py-2.5 sm:py-3 px-4 block w-full border-gray-200 rounded-lg border sm:text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600">
</div>
<div>
<label for="sponsormail" class="block mb-2 text-sm text-gray-700 font-medium dark:text-white">{{
$t('e_mail_des_sponsors') }}</label>
<input v-bind="newsponsor_mail" type="email" name="sponsormail" id="sponsormail"
class="py-2.5 sm:py-3 px-4 block w-full border-gray-200 rounded-lg border sm:text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600">
</div>
</div>
<div>
<label for="eurokilometer" class="block mb-2 text-sm text-gray-700 font-medium dark:text-white">{{
$t('sponsoring_pro_kilometer_in_eur') }}</label>
<input v-bind="newsponsor_value" type="number" name="eurokilometer" id="eurokilometer"
placeholder="z.B. 1€ ODER 0,50€"
class="py-2.5 sm:py-3 px-4 block w-full border-gray-200 rounded-lg border sm:text-sm focus:border-blue-500 focus:ring-blue-500 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-900 dark:border-neutral-700 dark:text-neutral-400 dark:placeholder-neutral-500 dark:focus:ring-neutral-600">
</div>
</div>
</form>
<!-- End Grid -->
<!-- Checkbox -->
<div class="mt-3 flex">
<div class="flex">
<input v-model="newsponsor_check" id="sponsor_agree" name="sponsor_agree" type="checkbox"
class="shrink-0 mt-1.5 border-gray-200 rounded-sm text-blue-600 focus:ring-blue-500 dark:bg-neutral-800 dark:border-neutral-700 dark:checked:bg-blue-500 dark:checked:border-blue-500 dark:focus:ring-offset-gray-800">
</div>
<div class="ms-3">
<label for="sponsor_agree" class="text-sm text-gray-600 dark:text-neutral-400">{{
$t('sponsor_add_agree') }}</label>
</div>
</div>
<!-- End Checkbox -->
<button :disabled="!newsponsor_check" @click="addSponsoring" type="button"
class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-teal-100 text-teal-800 hover:bg-teal-200 focus:outline-hidden focus:bg-teal-200 disabled:opacity-50 disabled:pointer-events-none dark:text-teal-500 dark:bg-teal-800/30 dark:hover:bg-teal-800/20 dark:focus:bg-teal-800/20 mt-2 cursor-pointer">
{{ $t('add_sponsoring') }}
</button>
</div>
<div v-else>
<div class="py-4 w-full">
<section class="dark:bg-gray-900 body-font">
<div class="container mx-auto">
<div class="lg:w-2/3 w-full mx-auto overflow-auto">
<table v-if="state.sponsorings.length > 0" class="table-auto w-full text-left whitespace-no-wrap">
<thead class="
text-black
bg-gray-300
dark:text-white dark:text-white
text-sm text-sm
dark:bg-gray-800 dark:bg-gray-800
"> ">
<tr> <tr>
<th class=" <th class="
px-4 px-4
py-3 py-3
title-font title-font
tracking-wider tracking-wider
font-medium font-medium
"> ">
Name Name
</th> </th>
<th class=" <th class="
px-4
py-3
title-font
tracking-wider
font-medium
">
{{ $t("amount_per_kilometer_in_eur") }}
</th>
<th class="
px-4 px-4
py-3 py-3
title-font title-font
tracking-wider tracking-wider
font-medium font-medium
"> ">
{{ $t("amount_per_kilometer_in_eur") }} {{ $t("current_total_amount_in_eur") }}
</th> </th>
<th class=" </tr>
px-4 </thead>
py-3 <tbody class="text-gray-900 dark:text-gray-50">
title-font <tr class="odd:bg-white even:bg-gray-100 dark:odd:bg-neutral-900 dark:even:bg-neutral-800"
tracking-wider v-for="s in state.sponsorings" :key="s.id">
font-medium <td class="px-4 py-3">
"> <span v-text="s.donor.firstname + ' '"></span>
{{ $t("current_total_amount_in_eur") }} <span v-if="s.donor.middlename">
</th> <span v-text="s.donor.middlename"></span>
</tr> </span>
</thead> <span v-text="s.donor.lastname"></span>
<tbody class="text-gray-900 dark:text-gray-50"> </td>
<tr v-for="s in state.sponsorings" :key="s.id"> <td class="px-4 py-3">
<td class="px-4 py-3"> <span v-text="(s.amountPerDistance / 100)
<span v-text="s.donor.firstname"></span> .toFixed(2)
<span v-if="s.donor.middlename"> .toLocaleString('de-DE', { valute: 'EUR' })
<span v-text="s.donor.middlename"></span> "></span>
</span> </td>
<span v-text="s.donor.lastname"></span> <td class="px-4 py-3">
</td> <span v-text="(s.amount / 100)
<td class="px-4 py-3"> .toFixed(2)
<span v-text="(s.amountPerDistance / 100) .toLocaleString('de-DE', { valute: 'EUR' })
.toFixed(2) "></span>
.toLocaleString('de-DE', { valute: 'EUR' }) </td>
"></span> </tr>
</td> </tbody>
<td class="px-4 py-3"> <tfoot class="text-black
<span v-text="(s.amount / 100) bg-gray-300
.toFixed(2) border-t-2
.toLocaleString('de-DE', { valute: 'EUR' }) border-t-current
"></span> dark:text-white
</td> text-sm
</tr> dark:bg-gray-800">
</tbody> <tr>
<tfoot class="text-gray-900 dark:text-gray-50"> <td class="px-4 py-3">{{ $t("total") }}</td>
<tr> <td class="px-4 py-3">
<td class="px-4 py-3">{{ $t("total") }}</td> <span v-text="(
<td class="px-4 py-3"> state.sponsorings.reduce(function (
<span v-text="( sum,
state.sponsorings.reduce(function ( current
sum, ) {
current return sum + current.amountPerDistance;
) { },
return sum + current.amountPerDistance; 0) / 100
}, )
0) / 100 .toFixed(2)
) .toLocaleString('de-DE', { valute: 'EUR' })
.toFixed(2) "></span>
.toLocaleString('de-DE', { valute: 'EUR' }) </td>
"></span> <td class="px-4 py-3">
</td> <span v-text="(
<td class="px-4 py-3"> state.sponsorings.reduce(function (
<span v-text="( sum,
state.sponsorings.reduce(function ( current
sum, ) {
current return sum + current.amount;
) { },
return sum + current.amount; 0) / 100
}, )
0) / 100 .toFixed(2)
) .toLocaleString('de-DE', { valute: 'EUR' })
.toFixed(2) "></span>
.toLocaleString('de-DE', { valute: 'EUR' }) </td>
"></span> </tr>
</td> </tfoot>
</tr> </table>
</tfoot> <div v-else class="
</table>
<div v-else class="
text-center text-center
font-bold font-medium
text-black text-black
dark:text-white dark:text-white
text-2xl text-xl
"> ">
<img src="../assets/empty_laps.svg" style="height: 25rem; margin: 0 auto" :alt="[ <img src="../assets/empty_laps.svg" class="h-56 mx-auto" :alt="[
[$t('no_sponsorings_for_you_were_recorded_yet')], [$t('no_sponsorings_for_you_were_recorded_yet')],
]" /> ]" />
{{ $t("no_sponsorings_for_you_were_recorded_yet") }} {{ $t("no_sponsorings_for_you_were_recorded_yet") }}
</div>
<!-- <button
class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-teal-100 text-teal-800 hover:bg-teal-200 focus:outline-hidden focus:bg-teal-200 disabled:opacity-50 disabled:pointer-events-none dark:text-teal-500 dark:bg-teal-800/30 dark:hover:bg-teal-800/20 dark:focus:bg-teal-800/20 mt-2"
@click="mode = 'add_sponsoring'">{{ $t('add_sponsoring') }}</button> -->
</div> </div>
</div> </div>
</div> </section>
</section> </div>
</div> </div>
</div> </div>
</div> </div>
@ -480,18 +490,35 @@
</template> </template>
<script setup> <script setup>
import { reactive } from "vue"; import { reactive, ref } from "vue";
import { TYPE, useToast } from "vue-toastification"; import { TYPE, useToast } from "vue-toastification";
import axios from "redaxios"; import axios from "redaxios";
import { toCanvas } from "bwip-js"; import { toCanvas } from "bwip-js";
import Footer from "@/components/Footer.vue"; import Footer from "@/components/Footer.vue";
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
const { t } = useI18n() const { t } = useI18n()
const loadstate = ref("loading")
const mode = ref("")
//
const newsponsor_check = ref(false)
const newsponsor_value = ref("")
const newsponsor_mail = ref("")
const newsponsor_tel = ref("")
const newsponsor_vorname = ref("")
const newsponsor_nachname = ref("")
function shareSponsorLink() {
navigator.share({
title: state.firstname,
text: "Am 23.05.2025 findet der Lauf für Kaya! statt 🏃‍♂️🏃‍♀️\nWerde mein Sponsor beim Lauf für Kaya! 2025 und unterstütze mich pro gelaufenem Kilometer: https://lauf-fuer-kaya.de",
// url: "https://lauf-fuer-kaya.de",
})
}
function textToBase64Barcode(text) { function textToBase64Barcode(text) {
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
let codeconfig = { let codeconfig = {
bcid: config.code_format || "code39", bcid: config.code_format || "code128",
text: `${text}`, text: `${text}`,
scale: 3, scale: 3,
includetext: false, includetext: false,
@ -527,10 +554,26 @@ const toast = useToast();
const props = defineProps({ const props = defineProps({
token: String, token: String,
}); });
const accesstoken = atob(props.token); const accesstoken = props.token;
function getReadableDistanceForUI() {
return state.scans.reduce((accumulator, currentValue) => accumulator + currentValue.distance, 0)
}
function getReadableDistance(distance) {
const km = Math.floor(distance / 1000)
const m = Math.floor(distance % 1000)
console.log({ km, m });
if (km > 0) {
return `${km},${m} km`
}
return `${m} m`
}
axios axios
.get(`${config.baseurl}api/runners/me/${accesstoken}`) .get(`${config.baseurl}api/runners/me/${accesstoken}`)
.then(({ data }) => { .then(({ data }) => {
loadstate.value = "loaded"
state.phone = data.phone; state.phone = data.phone;
state.email = data.email; state.email = data.email;
state.firstname = data.firstname; state.firstname = data.firstname;
@ -542,23 +585,26 @@ axios
state.barcode = textToBase64Barcode(data.id ?? "???"); state.barcode = textToBase64Barcode(data.id ?? "???");
}) })
.catch((error) => { .catch((error) => {
loadstate = "error"
toast.clear(); toast.clear();
toast.error(t('profil_konnte_nicht_geladen_werden')); toast.error(t('profil_konnte_nicht_geladen_werden'));
}); });
axios axios
.get(`${config.baseurl}api/runners/me/${accesstoken}/scans`) .get(`${config.baseurl}api/runners/me/${accesstoken}/scans`)
.then(({ data }) => { .then(({ data }) => {
let counter = 0
data.map(function (s) { data.map(function (s) {
s.lapTime = if (counter === 0) {
Math.floor(s.lapTime / 60) + s.lapTime_readable = t('first_lap')
"min " + } else {
(Math.floor(s.lapTime % 60) + "").padStart(2, "0") + s.lapTime_readable =
"s"; Math.floor(s.lapTime / 60) +
s.distance = "min " +
Math.floor(s.distance / 1000) + (Math.floor(s.lapTime % 60) + "").padStart(2, "0") +
"km " + "s";
(Math.floor(s.distance % 1000) + "").padStart(3, "0") + }
"m"; s.distance_readable = getReadableDistance(s.distance);
counter++;
return s; return s;
}); });
data.filter((s) => s.valid === true); data.filter((s) => s.valid === true);
@ -567,6 +613,26 @@ axios
.catch((error) => { .catch((error) => {
toast.error(t('profil_konnte_nicht_geladen_werden')); toast.error(t('profil_konnte_nicht_geladen_werden'));
}); });
function addSponsoring() {
const postdata = {
"receiptNeeded": false,
"firstname": newsponsor_vorname.value,
"middlename": "",
"lastname": newsponsor_nachname.value,
"phone": newsponsor_tel.value,
"email": newsponsor_mail.value,
"address": {}
}
console.log(postdata);
axios
.post(`${config.baseurl}api/donors`, postdata)
.then(({ data }) => {
console.log(data);
})
.catch((error) => {
//
});
}
function delete_me() { function delete_me() {
toast.clear(); toast.clear();
toast(t('profil_wird_geloescht')); toast(t('profil_wird_geloescht'));
@ -589,12 +655,36 @@ function get_certificate() {
(navigator.languages && navigator.languages[0]) || (navigator.languages && navigator.languages[0]) ||
"" ""
).substr(0, 2); ).substr(0, 2);
let url = `${config.baseurl_documentserver}certificates?locale=${browserlocale}&download=true&key=${config.documentserver_key}`; let url = `${config.baseurl_documentserver}/v1/pdfs/certificates?key=${config.documentserver_key}`;
let postdata = Object.assign({}, state.fullobject); let postdata = {
postdata.group = { locale: browserlocale,
name: postdata.group, runners: [
{
first_name: state.firstname,
middle_name: state.middlename,
last_name: state.lastname,
id: state.fullobject.id,
distance: state.fullobject.distance,
group: {
name: state.group,
id: state.fullobject.group.id || 0,
},
distance_donations: state.fullobject.distanceDonations.map((s) => {
return {
id: s.id || 0,
amount: s.amount,
amount_per_distance: s.amountPerDistance,
donor: {
id: s.donor.id || 0,
first_name: s.donor.firstname,
middle_name: s.donor.middlename,
last_name: s.donor.lastname,
},
};
}),
}
]
}; };
postdata = [postdata];
axios axios
.post(url, postdata, { .post(url, postdata, {
responseType: "blob", responseType: "blob",