Compare commits

...

17 Commits

Author SHA1 Message Date
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
10 changed files with 1548 additions and 1579 deletions

View File

@@ -2,9 +2,32 @@
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.2](https://git.odit.services/lfk/selfservice/compare/1.2.1...1.2.2)
- feat(profile): add cursor pointer [`1d7cd60`](https://git.odit.services/lfk/selfservice/commit/1d7cd601ee027dd7df0405079e208d03078210bb)
#### [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) #### [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) - 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) - 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) - fix(profile): migrate to code128 [`762454a`](https://git.odit.services/lfk/selfservice/commit/762454a08674303881063337ddf86da564b191f1)

View File

@@ -1,6 +1,6 @@
{ {
"name": "@odit/lfk-selfservice", "name": "@odit/lfk-selfservice",
"version": "1.1.2", "version": "1.2.2",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -8,12 +8,12 @@
"release": "release-it" "release": "release-it"
}, },
"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",
@@ -22,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.3", "vite": "6.2.2",
"vite-plugin-vue-devtools": "7.6.8" "vite-plugin-vue-devtools": "7.7.2"
}, },
"release-it": { "release-it": {
"git": { "git": {

2290
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

@@ -18,6 +18,7 @@
"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 +32,7 @@
"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 ...", "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",
@@ -63,6 +64,7 @@
"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 File

@@ -18,6 +18,7 @@
"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.",
@@ -63,6 +64,7 @@
"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 File

@@ -1 +1,5 @@
@import "tailwindcss"; @import "tailwindcss";
* {
font-family: Athiti;
}

View File

@@ -1,52 +1,70 @@
<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" />
' ' + <h1 class="text-3xl font-bold whitespace-nowrap font-[Athiti]" v-text="(state.firstname || '') +
(state.middlename || '') + ' ' +
' ' + (state.middlename || '') +
(state.lastname || '') ' ' +
"></p> (state.lastname || '')
<p class="text-md whitespace-nowrap">{{ state.group }}</p> "></h1>
</div> <p class="text-md whitespace-nowrap">Team: {{ state.group }}</p>
<div class="inline-flex md:ml-auto md:mr-0 mx-auto items-center"> </div>
<div v-if="state.delete_active === false"> <div class="flex flex-wrap">
<button type="button" class=" <div class="w-full">
focus:border-black focus:ring-2 focus:ring-black <div class="flex flex-wrap flex-col w-full tabs">
text-white text-base md:text-sm <div class="flex lg:flex-wrap flex-row lg:space-x-2 justify-center">
py-3.5 <div class="flex-none">
px-5 <button @click="() => {
md:py-2.5 state.activetab = 'profile';
md:px-5 }
rounded-md " :class="{
bg-blue-500 'tab-active border-b-2 font-medium border-blue-500':
hover:bg-blue-600 hover:shadow-lg state.activetab === 'profile',
w-full }" class="tab tab-underline cursor-pointer py-4 px-6 block" type="button">
md:w-auto {{ $t("profile") }}
mb-1 </button>
md:mr-1 </div>
" @click="get_registration"> <div class="flex-none">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" <button @click="() => {
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" state.activetab = 'laptimes';
class="feather feather-download" style="display: inline; height: 1rem; vertical-align: sub"> }
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /> " :class="{
<polyline points="7 10 12 15 17 10" /> 'tab-active border-b-2 font-medium border-blue-500':
<line x1="12" y1="15" x2="12" y2="3" /> state.activetab === 'laptimes',
</svg> }" class="tab tab-underline cursor-pointer py-4 px-6 block" type="button">
{{ $t("download_registrationcode") }} {{ $t("lap_times") }}
</button> </button>
<button type="button" class=" </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 +76,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 +102,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 +144,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,173 +169,58 @@
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">
<p class="mb-2">
{{ $t('total_distance') }}: {{ getReadableDistanceForUI() }}
</p>
<table v-if="state.scans.length > 0" class="table-auto w-full text-left whitespace-no-wrap"> <table v-if="state.scans.length > 0" class="table-auto w-full text-left whitespace-no-wrap">
<thead class=" <thead class="
text-black text-black
@@ -332,9 +253,9 @@
<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>
@@ -355,120 +276,210 @@
</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">Sponsoring hinzufügen</h1>
<div class="container mx-auto">
<div class="lg:w-2/3 w-full mx-auto overflow-auto"> <form>
<table v-if="state.sponsorings.length > 0" class="table-auto w-full text-left whitespace-no-wrap"> <div class="mt-6 grid gap-4 lg:gap-6">
<thead class=" <!-- Grid -->
text-black <div class="grid grid-cols-1 sm:grid-cols-2 gap-4 lg:gap-6">
bg-gray-300 <div>
<label for="sponsorvorname"
class="block mb-2 text-sm text-gray-700 font-medium dark:text-white">Vorname</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">Nachname</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">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">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">Sponsoring pro Kilometer in
€</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">Mit dem Absenden
bestätige ich, dass der Sponsor mit der Übermittlung seiner Daten einverstanden ist und ich dessen
Berechtigung habe</label>
</div>
</div>
<!-- End Checkbox -->
<!-- <div class="mt-6 grid"> -->
<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">
Sponsoring hinzufügen
</button>
<!-- <button type="submit"
class="w-full py-3 px-4 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-hidden focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none">Sponsoring
hinzufügen</button> -->
<!-- </div> -->
</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 v-for="s in state.sponsorings" :key="s.id">
tracking-wider <td class="px-4 py-3">
font-medium <span v-text="s.donor.firstname + ' '"></span>
"> <span v-if="s.donor.middlename">
{{ $t("current_total_amount_in_eur") }} <span v-text="s.donor.middlename"></span>
</th> </span>
</tr> <span v-text="s.donor.lastname"></span>
</thead> </td>
<tbody class="text-gray-900 dark:text-gray-50"> <td class="px-4 py-3">
<tr v-for="s in state.sponsorings" :key="s.id"> <span v-text="(s.amountPerDistance / 100)
<td class="px-4 py-3"> .toFixed(2)
<span v-text="s.donor.firstname"></span> .toLocaleString('de-DE', { valute: 'EUR' })
<span v-if="s.donor.middlename"> "></span>€
<span v-text="s.donor.middlename"></span> </td>
</span> <td class="px-4 py-3">
<span v-text="s.donor.lastname"></span> <span v-text="(s.amount / 100)
</td> .toFixed(2)
<td class="px-4 py-3"> .toLocaleString('de-DE', { valute: 'EUR' })
<span v-text="(s.amountPerDistance / 100) "></span>€
.toFixed(2) </td>
.toLocaleString('de-DE', { valute: 'EUR' }) </tr>
"></span>€ </tbody>
</td> <tfoot class="text-black
<td class="px-4 py-3"> bg-gray-300
<span v-text="(s.amount / 100) border-t-2
.toFixed(2) border-t-current
.toLocaleString('de-DE', { valute: 'EUR' }) dark:text-white
"></span>€ text-sm
</td> dark:bg-gray-800">
</tr> <tr>
</tbody> <td class="px-4 py-3">{{ $t("total") }}</td>
<tfoot class="text-gray-900 dark:text-gray-50"> <td class="px-4 py-3">
<tr> <span v-text="(
<td class="px-4 py-3">{{ $t("total") }}</td> state.sponsorings.reduce(function (
<td class="px-4 py-3"> sum,
<span v-text="( current
state.sponsorings.reduce(function ( ) {
sum, return sum + current.amountPerDistance;
current },
) { 0) / 100
return sum + current.amountPerDistance; )
}, .toFixed(2)
0) / 100 .toLocaleString('de-DE', { valute: 'EUR' })
) "></span>€
.toFixed(2) </td>
.toLocaleString('de-DE', { valute: 'EUR' }) <td class="px-4 py-3">
"></span>€ <span v-text="(
</td> state.sponsorings.reduce(function (
<td class="px-4 py-3"> sum,
<span v-text="( current
state.sponsorings.reduce(function ( ) {
sum, return sum + current.amount;
current },
) { 0) / 100
return sum + current.amount; )
}, .toFixed(2)
0) / 100 .toLocaleString('de-DE', { valute: 'EUR' })
) "></span>€
.toFixed(2) </td>
.toLocaleString('de-DE', { valute: 'EUR' }) </tr>
"></span>€ </tfoot>
</td> </table>
</tr> <div v-else class="
</tfoot>
</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'">Sponsoring hinzufügen</button>
</div> </div>
</div> </div>
</div> </section>
</section> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -480,13 +491,21 @@
</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 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 textToBase64Barcode(text) { function textToBase64Barcode(text) {
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
@@ -528,6 +547,21 @@ const props = defineProps({
token: String, token: String,
}); });
const accesstoken = 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 }) => {
@@ -548,17 +582,19 @@ axios
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 +603,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 +645,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",