Compare commits

..

21 Commits

Author SHA1 Message Date
3b4c11e4c0 Merge branch 'feature/39-donation_list' of git.odit.services:lfk/selfservice into feature/39-donation_list 2021-04-06 21:25:12 +02:00
89820d4450 Added total to bottom of page
ref #39
2021-04-06 21:25:10 +02:00
121022c843 added distance formatting
ref #39
2021-04-06 21:23:24 +02:00
d713fbef94 Added translations 🌍
ref #39
2021-04-06 17:27:18 +02:00
815a36f202 Now w/ formatted currency amount
ref #39
2021-04-06 17:20:41 +02:00
baa6da3dd0 Fixed spaces in name
ref #39
2021-04-06 17:18:09 +02:00
f141130db5 Added basic sponsoring table
ref #39
2021-04-06 17:14:22 +02:00
5a123b0cf8 Updated env description
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-06 17:03:05 +02:00
f5ae2145df 🚀Bumped version to v0.6.1
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-06 17:01:20 +02:00
96c0e56986 Fixed imprint/privacy default links
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-06 17:00:55 +02:00
bc1de2acdc 🚀Bumped version to v0.6.0
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-03 18:53:32 +02:00
5c558aa9ee Merge branch 'dev' of git.odit.services:lfk/selfservice into dev 2021-04-03 18:53:14 +02:00
145b49906b Revert "🚀Bumped version to v0.6.0"
This reverts commit 0a62e8f5d1.
2021-04-03 18:53:12 +02:00
0a62e8f5d1 🚀Bumped version to v0.6.0 2021-04-03 18:52:54 +02:00
53eeb6be3d Merge pull request 'Certificate download feature/19-runner_certficates' (#38) from feature/19-runner_certficates into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #38
2021-04-03 16:51:22 +00:00
a554a90e74 Merge branch 'dev' into feature/19-runner_certficates
# Conflicts:
#	index.html
2021-04-03 18:50:16 +02:00
c3b2b93d90 Reverted relative linking fix
ref #19
2021-04-03 18:48:53 +02:00
7064a5bd82 Merge branch 'dev' into feature/19-runner_certficates 2021-04-03 16:28:18 +00:00
f0a7f35dec Renoved fixed data
ref #19
2021-04-03 18:11:57 +02:00
b938cfc49e Fixed blob handling
ref #19
2021-04-03 18:11:22 +02:00
f6334397dc first part of certificate generation with manual data
ref #19
2021-04-03 17:57:24 +02:00
8 changed files with 562 additions and 413 deletions

View File

@@ -2,9 +2,29 @@
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.
#### [0.6.1](https://git.odit.services/lfk/selfservice/compare/0.6.0...0.6.1)
- Fixed imprint/privacy default links [`96c0e56`](https://git.odit.services/lfk/selfservice/commit/96c0e5698697361e65c5aa80c9a0aada5c3d5f30)
#### [0.6.0](https://git.odit.services/lfk/selfservice/compare/0.5.1...0.6.0)
> 3 April 2021
- 🚀Bumped version to v0.6.0 [`bc1de2a`](https://git.odit.services/lfk/selfservice/commit/bc1de2acdcbf8f3319026887cb6b3d594fcd63dc)
- first part of certificate generation with manual data [`f633439`](https://git.odit.services/lfk/selfservice/commit/f6334397dc99cd38d31ef524bc26ba7d386b33dd)
- Renoved fixed data [`f0a7f35`](https://git.odit.services/lfk/selfservice/commit/f0a7f35dec07508a07d4c11abda297ad0bf91187)
- Revert "🚀Bumped version to v0.6.0" [`145b499`](https://git.odit.services/lfk/selfservice/commit/145b49906bdf2d75abf93e1779f188a691a3a909)
- 🚀Bumped version to v0.6.0 [`0a62e8f`](https://git.odit.services/lfk/selfservice/commit/0a62e8f5d1929bfe9a53a9709a3031f06a2487c3)
- Merge pull request 'Certificate download feature/19-runner_certficates' (#38) from feature/19-runner_certficates into dev [`53eeb6b`](https://git.odit.services/lfk/selfservice/commit/53eeb6be3ddf4735a11b6c4636c28b4d16aa58ee)
- Fixed blob handling [`b938cfc`](https://git.odit.services/lfk/selfservice/commit/b938cfc49e269e76761a752f8257ebbab88f6959)
- Reverted relative linking fix [`c3b2b93`](https://git.odit.services/lfk/selfservice/commit/c3b2b93d90102b4e31cfce15220acfc8fe48a7c5)
#### [0.5.1](https://git.odit.services/lfk/selfservice/compare/0.5.0...0.5.1) #### [0.5.1](https://git.odit.services/lfk/selfservice/compare/0.5.0...0.5.1)
> 3 April 2021
- Merge pull request 'feature/30-profile-forgot-link' (#35) from feature/30-profile-forgot-link into dev [`#30`](https://git.odit.services/lfk/selfservice/issues/30) - Merge pull request 'feature/30-profile-forgot-link' (#35) from feature/30-profile-forgot-link into dev [`#30`](https://git.odit.services/lfk/selfservice/issues/30)
- 🚀Bumped version to v0.5.1 [`1a3c9ed`](https://git.odit.services/lfk/selfservice/commit/1a3c9edeb3987907ffe2223da8f3be079a1c80d2)
- Merge pull request 'Env linking bugfix bugfix/31-env_linking' (#37) from bugfix/31-env_linking into dev [`fd6bd88`](https://git.odit.services/lfk/selfservice/commit/fd6bd88d4238cca2a2755ab1bc51ff7870bef947) - Merge pull request 'Env linking bugfix bugfix/31-env_linking' (#37) from bugfix/31-env_linking into dev [`fd6bd88`](https://git.odit.services/lfk/selfservice/commit/fd6bd88d4238cca2a2755ab1bc51ff7870bef947)
- basic ProfileNone layout [`863568d`](https://git.odit.services/lfk/selfservice/commit/863568d7d0e132dd1b7d13a2cb1afe8db02c472c) - basic ProfileNone layout [`863568d`](https://git.odit.services/lfk/selfservice/commit/863568d7d0e132dd1b7d13a2cb1afe8db02c472c)
- add forgot view + action [`30f3a51`](https://git.odit.services/lfk/selfservice/commit/30f3a51ef82ad966225abc6fd95508af56106924) - add forgot view + action [`30f3a51`](https://git.odit.services/lfk/selfservice/commit/30f3a51ef82ad966225abc6fd95508af56106924)

View File

@@ -10,8 +10,8 @@
<body class="dark:bg-gray-900 text-black dark:text-white p-0"> <body class="dark:bg-gray-900 text-black dark:text-white p-0">
<div id="app"></div> <div id="app"></div>
<script src="./env.js"></script> <script src="/env.js"></script>
<script defer type="module" src="./src/main.js"></script> <script defer type="module" src="/src/main.js"></script>
</body> </body>
</html> </html>

View File

@@ -1,6 +1,6 @@
{ {
"name": "@odit/lfk-selfservice", "name": "@odit/lfk-selfservice",
"version": "0.5.1", "version": "0.6.1",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",

View File

@@ -5,8 +5,8 @@ const config = {
baseurl: '', baseurl: '',
// optional, will fallback to /selfservice/ // optional, will fallback to /selfservice/
baseurl_selfservice: '/selfservice/', baseurl_selfservice: '/selfservice/',
// optional, will fallback to /imprint // optional, will fallback to baseurl_selfservice/imprint
url_imprint: '', url_imprint: '',
// optional, will fallback to /privacy // optional, will fallback to baseurl_selfservice/privacy
url_privacy: '' url_privacy: ''
}; };

View File

@@ -31,8 +31,8 @@
export default { export default {
data() { data() {
return { return {
imprint_url: config.url_imprint || "/imprint/" imprint_url: config.url_imprint || config.baseurl_selfservice + "imprint"
, privacy_url: config.url_privacy || "/privacy/" , privacy_url: config.url_privacy || config.baseurl_selfservice + "privacy"
} }
}, },
} }

View File

@@ -1,54 +1,58 @@
{ {
"access_is_only_provided_via_your_email_link": "Der Zugang erfolgt nur über den Link, den Sie bei der Registrierung erhalten haben.", "access_is_only_provided_via_your_email_link": "Der Zugang erfolgt nur über den Link, den Sie bei der Registrierung erhalten haben.",
"already_have_an_account": "Sie haben bereits einen Account?", "already_have_an_account": "Sie haben bereits einen Account?",
"apartment_suite_etc": "Addresszeile 2", "amount_per_kilometer_in_eur": "Betrag pro Kilometer (in €)",
"cancel_keep_my_data": "Abbrechen, meine Daten behalten", "apartment_suite_etc": "Addresszeile 2",
"configuration_error": "Konfigurationsfehler", "cancel_keep_my_data": "Abbrechen, meine Daten behalten",
"confirm_delete_all_of_my_data": "Bestätigung, meine gesamten Daten löschen", "configuration_error": "Konfigurationsfehler",
"confirm_personal_data": "Hiermit bestätige ich die Vollständigkeit und Richtigkeit der oben genannten Angaben", "confirm_delete_all_of_my_data": "Bestätigung, meine gesamten Daten löschen",
"delete-all-of-my-data": "Meine gesamten Daten löschen", "confirm_personal_data": "Hiermit bestätige ich die Vollständigkeit und Richtigkeit der oben genannten Angaben",
"delete_my_data": "Meine Daten löschen", "current_total_amount_in_eur": "Aktueller Gesamtbetrag (in €)",
"deletion_in_progress": "Daten werden gelöscht...", "delete_all_of_my_data": "Meine gesamten Daten löschen",
"distance": "Distanz", "delete_my_data": "Meine Daten löschen",
"download_certificate": "Urkunde herunterladen", "deletion_in_progress": "Daten werden gelöscht...",
"e_mail_adress": "E-Mail Adresse", "distance": "Distanz",
"go_to_login": "Zum Login", "download_certificate": "Urkunde herunterladen",
"i_accept": "Ich habe die ", "e_mail_adress": "E-Mail Adresse",
"i_accept_end": "gelesen und akzeptiert.", "go_to_login": "Zum Login",
"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.", "i_accept": "Ich habe die ",
"imprint": "Impressum", "i_accept_end": "gelesen und akzeptiert.",
"lap_time": "Rundenzeit", "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.",
"lap_times": "Rundenzeiten", "imprint": "Impressum",
"lost_your_registration_mail": "Haben Sie Ihre Registrierungsmail verloren?", "lap_time": "Rundenzeit",
"main_page_text": "Hier können Sie sich für den Lauf Für Kaya! registrieren oder ihr Läuferprofil verwalten.", "lap_times": "Rundenzeiten",
"mittelname": "Mittelname", "lost_your_registration_mail": "Haben Sie Ihre Registrierungsmail verloren?",
"nachname": "Nachname", "main_page_text": "Hier können Sie sich für den Lauf Für Kaya! registrieren oder ihr Läuferprofil verwalten.",
"no_laps_scans_were_recorded_yet": "Es wurden noch keine Runden / Scans aufgezeichnet ...", "mittelname": "Mittelname",
"not_registered_yet": "Noch nicht registriert?", "nachname": "Nachname",
"organization": "Organisation", "no_laps_scans_were_recorded_yet": "Es wurden noch keine Runden / Scans aufgezeichnet ...",
"ort": "Ort", "no_sponsorings_for_you_were_recorded_yet": "Es gibt noch keine Sponsorings für dich",
"phone_number": "Telefonnummer", "not_registered_yet": "Noch nicht registriert?",
"please_provide_a_valid_zipcode": "Bitte geben Sie eine gültige Postleitzahl an...", "organization": "Organisation",
"please_provide_valid_mail": "Bitte geben Sie eine gültige E-Mail Adresse an", "ort": "Ort",
"plz": "PLZ", "phone_number": "Telefonnummer",
"privacy_policy": "Datenschutzerklärung", "please_provide_a_valid_zipcode": "Bitte geben Sie eine gültige Postleitzahl an...",
"profile": "Profil", "please_provide_valid_mail": "Bitte geben Sie eine gültige E-Mail Adresse an",
"provide_address": "Adresse angeben?", "plz": "PLZ",
"register": { "privacy_policy": "Datenschutzerklärung",
"register_now": "Jetzt für den Lauf für Kaya! 2021 registrieren." "profile": "Profil",
}, "provide_address": "Adresse angeben?",
"register_now": "Jetzt registrieren!", "register": {
"register_now_small": "Jetzt registrieren", "register_now": "Jetzt für den Lauf für Kaya! 2021 registrieren."
"registrieren": "Registrieren", },
"resend_the_registration_mail": "Registrierungsmail erneut versenden", "register_now": "Jetzt registrieren!",
"save_changes": "Änderungen speichern", "register_now_small": "Jetzt registrieren",
"sponsoring": "Sponsoring", "registrieren": "Registrieren",
"strasse": "Straße", "resend_the_registration_mail": "Registrierungsmail erneut versenden",
"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.", "save_changes": "Änderungen speichern",
"this_is_not_a_valid_international_phone_number": "Dies ist keine gültige internationale Telefonnummer", "sponsoring": "Sponsoring",
"tos": "AGBs", "strasse": "Straße",
"view_my_data": "Meine Läuferdaten einsehen", "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.",
"vorname": "Vorname", "this_is_not_a_valid_international_phone_number": "Dies ist keine gültige internationale Telefonnummer",
"you_have_been_registered": "Sie wurden registriert!", "tos": "AGBs",
"you_have_not_provided_a_valid_access_key": "Sie haben keinen gültigen Zugangsschlüssel angegeben..." "view_my_data": "Meine Läuferdaten einsehen",
} "vorname": "Vorname",
"you_have_been_registered": "Sie wurden registriert!",
"you_have_not_provided_a_valid_access_key": "Sie haben keinen gültigen Zugangsschlüssel angegeben...",
"total": "Gesamt"
}

View File

@@ -1,54 +1,58 @@
{ {
"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.",
"all_data_deleted": "All Data deleted!", "all_data_deleted": "All Data deleted!",
"already_have_an_account": "Already have an account?", "already_have_an_account": "Already have an account?",
"apartment_suite_etc": "Apartment, suite, etc.", "amount_per_kilometer_in_eur": "Amount per kilometer (in €)",
"cancel_keep_my_data": "Cancel, keep my data", "apartment_suite_etc": "Apartment, suite, etc.",
"configuration_error": "Configuration error", "cancel_keep_my_data": "Cancel, keep my data",
"confirm_delete_all_of_my_data": "Confirm, delete all of my data", "configuration_error": "Configuration error",
"confirm_personal_data": "I hereby confirm that the above information is complete and correct", "confirm_delete_all_of_my_data": "Confirm, delete all of my data",
"delete_my_data": "Delete my data", "confirm_personal_data": "I hereby confirm that the above information is complete and correct",
"deletion_in_progress": "Deletion in progress...", "current_total_amount_in_eur": "Current total amount (in €)",
"distance": "Distance", "delete_my_data": "Delete my data",
"download_certificate": "Download certificate", "deletion_in_progress": "Deletion in progress...",
"e_mail_adress": "mail address", "distance": "Distance",
"go_to_login": "Go To Login", "download_certificate": "Download certificate",
"i_accept": "I have read and accepted the ", "e_mail_adress": "mail address",
"i_accept_end": "", "go_to_login": "Go To Login",
"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.", "i_accept": "I have read and accepted the ",
"imprint": "Imprint", "i_accept_end": "",
"lap_time": "Lap time", "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.",
"lap_times": "Lap times", "imprint": "Imprint",
"lost_your_registration_mail": "Lost your registration mail?", "lap_time": "Lap time",
"main_page_text": "Here you can register for the Lauf Für Kaya! or manage your runner profile.", "lap_times": "Lap times",
"mittelname": "Middlename", "lost_your_registration_mail": "Lost your registration mail?",
"nachname": "Lastname", "main_page_text": "Here you can register for the Lauf Für Kaya! or manage your runner profile.",
"no_laps_scans_were_recorded_yet": "No laps/ scans were recorded yet...", "mittelname": "Middlename",
"not_registered_yet": "Not registered yet?", "nachname": "Lastname",
"organization": "Organization", "no_laps_scans_were_recorded_yet": "No laps/ scans were recorded yet...",
"ort": "City", "no_sponsorings_for_you_were_recorded_yet": "No sponsorings for you were recorded yet...",
"phone_number": "Phone Number", "not_registered_yet": "Not registered yet?",
"please_provide_a_valid_zipcode": "Please provide a valid zipcode...", "organization": "Organization",
"please_provide_valid_mail": "Please provide a valid mail address.", "ort": "City",
"plz": "zipcode", "phone_number": "Phone Number",
"privacy_policy": "Privacy Policy", "please_provide_a_valid_zipcode": "Please provide a valid zipcode...",
"profile": "Profile", "please_provide_valid_mail": "Please provide a valid mail address.",
"provide_address": "Provide a postal address?", "plz": "zipcode",
"register": { "privacy_policy": "Privacy Policy",
"register_now": "Register now for Lauf für Kaya! 2021." "profile": "Profile",
}, "provide_address": "Provide a postal address?",
"register_now": "Register now!", "register": {
"register_now_small": "Register now", "register_now": "Register now for Lauf für Kaya! 2021."
"registrieren": "Register Now", },
"resend_the_registration_mail": "Resend the registration mail", "register_now": "Register now!",
"save_changes": "Save changes", "register_now_small": "Register now",
"sponsoring": "Sponsoring", "registrieren": "Register Now",
"strasse": "Street/ Block", "resend_the_registration_mail": "Resend the registration mail",
"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.", "save_changes": "Save changes",
"this_is_not_a_valid_international_phone_number": "This is not a valid international phone number", "sponsoring": "Sponsoring",
"tos": "Terms of Service", "strasse": "Street/ Block",
"view_my_data": "View my data", "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.",
"vorname": "Firstname", "this_is_not_a_valid_international_phone_number": "This is not a valid international phone number",
"you_have_been_registered": "You have been registered!", "tos": "Terms of Service",
"you_have_not_provided_a_valid_access_key": "You have not provided a valid access key..." "view_my_data": "View my data",
} "vorname": "Firstname",
"you_have_been_registered": "You have been registered!",
"you_have_not_provided_a_valid_access_key": "You have not provided a valid access key...",
"total": "Total"
}

View File

@@ -1,301 +1,422 @@
<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"> <section class="text-white body-font">
<div class="container mx-auto flex items-center md:flex-row flex-col"> <div class="container mx-auto flex items-center md:flex-row flex-col">
<div <div
class="flex flex-col md:pr-10 md:mb-0 mb-6 pr-0 w-full md:w-auto md:text-left text-center text-black dark:text-gray-200" class="flex flex-col md:pr-10 md:mb-0 mb-6 pr-0 w-full md:w-auto md:text-left text-center text-black dark:text-gray-200"
> >
<p <p
class="text-3xl font-bold whitespace-nowrap" class="text-3xl font-bold whitespace-nowrap"
v-text="(state.firstname || '') + ' ' + (state.middlename || '') + ' ' + (state.lastname || '')" v-text="(state.firstname || '') + ' ' + (state.middlename || '') + ' ' + (state.lastname || '')"
></p> ></p>
<p class="text-md whitespace-nowrap">{{ state.group }}</p> <p class="text-md whitespace-nowrap">{{ state.group }}</p>
</div> </div>
<div class="inline-flex md:ml-auto md:mr-0 mx-auto items-center"> <div class="inline-flex md:ml-auto md:mr-0 mx-auto items-center">
<div v-if="(state.delete_active === false)"> <div v-if="(state.delete_active === false)">
<button <button
type="button" type="button"
class="focus:border-black focus:ring-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md bg-blue-500 hover:bg-blue-600 hover:shadow-lg" class="focus:border-black focus:ring-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md bg-blue-500 hover:bg-blue-600 hover:shadow-lg"
> @click="get_certificate"
<svg >
xmlns="http://www.w3.org/2000/svg" <svg
width="24" xmlns="http://www.w3.org/2000/svg"
height="24" width="24"
viewBox="0 0 24 24" height="24"
fill="none" viewBox="0 0 24 24"
stroke="currentColor" fill="none"
stroke-width="2" stroke="currentColor"
stroke-linecap="round" stroke-width="2"
stroke-linejoin="round" stroke-linecap="round"
class="feather feather-download" stroke-linejoin="round"
style="display: inline;height: 1rem;vertical-align: sub;" 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" /> >
<polyline points="7 10 12 15 17 10" /> <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<line x1="12" y1="15" x2="12" y2="3" /> <polyline points="7 10 12 15 17 10" />
</svg> <line x1="12" y1="15" x2="12" y2="3" />
{{ $t('download_certificate') }} </svg>
</button> {{ $t('download_certificate') }}
<button </button>
type="button" <button
class="focus:border-black focus:ring-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md bg-red-600 hover:bg-red-700 hover:shadow-lg ml-1" type="button"
@click="() => { state.delete_active = true }" class="focus:border-black focus:ring-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md bg-red-600 hover:bg-red-700 hover:shadow-lg ml-1"
> @click="() => { state.delete_active = true }"
<svg >
xmlns="http://www.w3.org/2000/svg" <svg
width="24" xmlns="http://www.w3.org/2000/svg"
height="24" width="24"
viewBox="0 0 24 24" height="24"
fill="none" viewBox="0 0 24 24"
stroke="none" fill="none"
stroke-width="2" stroke="none"
stroke-linecap="round" stroke-width="2"
stroke-linejoin="round" stroke-linecap="round"
class="feather feather-download" stroke-linejoin="round"
style="display: inline;height: 1rem;vertical-align: sub;" class="feather feather-download"
> style="display: inline;height: 1rem;vertical-align: sub;"
<path d="M0 0h24v24H0z" /> >
<path <path d="M0 0h24v24H0z" />
fill="currentColor" <path
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" 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"
</svg> />
{{ $t('delete_my_data') }} </svg>
</button> {{ $t('delete_my_data') }}
</div> </button>
<div v-if="(state.delete_active === true)"> </div>
<button <div v-if="(state.delete_active === true)">
type="button" <button
class="focus:border-black focus:ring-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md bg-blue-500 hover:bg-blue-600 hover:shadow-lg" type="button"
@click="() => { state.delete_active = false }" class="focus:border-black focus:ring-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md bg-blue-500 hover:bg-blue-600 hover:shadow-lg"
> @click="() => { state.delete_active = false }"
<svg >
xmlns="http://www.w3.org/2000/svg" <svg
width="24" xmlns="http://www.w3.org/2000/svg"
height="24" width="24"
viewBox="0 0 24 24" height="24"
fill="none" viewBox="0 0 24 24"
stroke="none" fill="none"
stroke-width="2" stroke="none"
stroke-linecap="round" stroke-width="2"
stroke-linejoin="round" stroke-linecap="round"
class="feather feather-download" stroke-linejoin="round"
style="display: inline;height: 1rem;vertical-align: sub;" class="feather feather-download"
> style="display: inline;height: 1rem;vertical-align: sub;"
<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="none" d="M0 0h24v24H0z" />
</svg> <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" />
{{ $t('cancel_keep_my_data') }} </svg>
</button> {{ $t('cancel_keep_my_data') }}
<button </button>
type="button" <button
class="focus:border-black focus:ring-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md bg-red-600 hover:bg-red-700 hover:shadow-lg ml-1" type="button"
@click="delete_me" class="focus:border-black focus:ring-2 focus:ring-black text-white text-sm py-2.5 px-5 rounded-md bg-red-600 hover:bg-red-700 hover:shadow-lg ml-1"
> @click="delete_me"
<svg >
xmlns="http://www.w3.org/2000/svg" <svg
width="24" xmlns="http://www.w3.org/2000/svg"
height="24" width="24"
viewBox="0 0 24 24" height="24"
fill="none" viewBox="0 0 24 24"
stroke="none" fill="none"
stroke-width="2" stroke="none"
stroke-linecap="round" stroke-width="2"
stroke-linejoin="round" stroke-linecap="round"
class="feather feather-download" stroke-linejoin="round"
style="display: inline;height: 1rem;vertical-align: sub;" class="feather feather-download"
> style="display: inline;height: 1rem;vertical-align: sub;"
<path d="M0 0h24v24H0z" /> >
<path <path d="M0 0h24v24H0z" />
fill="currentColor" <path
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" 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"
</svg> />
{{ $t('confirm_delete_all_of_my_data') }} </svg>
</button> {{ $t('confirm_delete_all_of_my_data') }}
</div> </button>
</div> </div>
</div> </div>
</section> </div>
<div class="flex flex-wrap"> </section>
<div class="w-full p-4"> <div class="flex flex-wrap">
<div class="flex flex-wrap flex-col w-full tabs"> <div class="w-full p-4">
<div class="flex lg:flex-wrap flex-row lg:space-x-2"> <div class="flex flex-wrap flex-col w-full tabs">
<div class="flex-none"> <div class="flex lg:flex-wrap flex-row lg:space-x-2">
<button <div class="flex-none">
@click="() => { state.activetab = 'profile' }" <button
:class="{ 'tab-active border-b-2 font-medium border-blue-500': (state.activetab === 'profile') }" @click="() => { state.activetab = 'profile' }"
class="tab tab-underline py-4 px-6 block" :class="{ 'tab-active border-b-2 font-medium border-blue-500': (state.activetab === 'profile') }"
type="button" class="tab tab-underline py-4 px-6 block"
>{{ $t('profile') }}</button> type="button"
</div> >{{ $t('profile') }}</button>
<div class="flex-none"> </div>
<button <div class="flex-none">
@click="() => { state.activetab = 'laptimes' }" <button
:class="{ 'tab-active border-b-2 font-medium border-blue-500': (state.activetab === 'laptimes') }" @click="() => { state.activetab = 'laptimes' }"
class="tab tab-underline py-4 px-6 block" :class="{ 'tab-active border-b-2 font-medium border-blue-500': (state.activetab === 'laptimes') }"
type="button" class="tab tab-underline py-4 px-6 block"
>{{ $t('lap_times') }}</button> type="button"
</div> >{{ $t('lap_times') }}</button>
<div class="flex-none"> </div>
<button <div class="flex-none">
@click="() => { state.activetab = 'sponsorings' }" <button
:class="{ 'tab-active border-b-2 font-medium border-blue-500': (state.activetab === 'sponsorings') }" @click="() => { state.activetab = 'sponsorings' }"
class="tab tab-underline py-4 px-6 block" :class="{ 'tab-active border-b-2 font-medium border-blue-500': (state.activetab === 'sponsorings') }"
type="button" class="tab tab-underline py-4 px-6 block"
>{{ $t('sponsoring') }}</button> type="button"
</div> >{{ $t('sponsoring') }}</button>
</div> </div>
<div v-if="(state.activetab === 'profile')" class="tab-content block"> </div>
<div class="py-4 w-full"> <div v-if="(state.activetab === 'profile')" class="tab-content block">
<div class="flex flex-col"> <div class="py-4 w-full">
<form class="form flex flex-wrap w-full"> <div class="flex flex-col">
<div class="w-full"> <form class="form flex flex-wrap w-full">
<div class="form-element"> <div class="w-full">
<div class="text-lg">{{ $t('vorname') }}</div> <div class="form-element">
<p <div class="text-lg">{{ $t('vorname') }}</div>
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" <p
v-text="state.firstname" 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>
<div class="text-lg">{{ $t('mittelname') }}</div> <div class="form-element">
<p <div class="text-lg">{{ $t('mittelname') }}</div>
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" <p
v-text="state.middlename" 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>
<div class="text-lg">{{ $t('nachname') }}</div> <div class="form-element">
<p <div class="text-lg">{{ $t('nachname') }}</div>
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" <p
v-text="state.lastname" 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>
<div class="text-lg">{{ $t('e_mail_adress') }}</div> <div class="form-element">
<p <div class="text-lg">{{ $t('e_mail_adress') }}</div>
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" <p
v-text="state.email" 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>
<div class="text-lg">{{ $t('phone_number') }}</div> <div class="form-element">
<p <div class="text-lg">{{ $t('phone_number') }}</div>
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" <p
v-text="state.phone" 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> </div>
</form> </div>
</div> </form>
</div> </div>
</div> </div>
<div v-if="(state.activetab === 'laptimes')" class="tab-content block"> </div>
<div class="py-4 w-full"> <div v-if="(state.activetab === 'laptimes')" class="tab-content block">
<section class="text-gray-400 dark:bg-gray-900 body-font"> <div class="py-4 w-full">
<div class="container mx-auto"> <section class="text-gray-400 dark:bg-gray-900 body-font">
<div class="lg:w-2/3 w-full mx-auto overflow-auto"> <div class="container mx-auto">
<table <div class="lg:w-2/3 w-full mx-auto overflow-auto">
v-if="state.scans.length > 0" <table
class="table-auto w-full text-left whitespace-no-wrap" v-if="state.scans.length > 0"
> class="table-auto w-full text-left whitespace-no-wrap"
<thead >
class="text-black bg-gray-300 dark:text-white text-sm dark:bg-gray-800" <thead
> class="text-black bg-gray-300 dark:text-white text-sm dark:bg-gray-800"
<tr> >
<th <tr>
class="px-4 py-3 title-font tracking-wider font-medium" <th
>{{ $t('distance') }}</th> class="px-4 py-3 title-font tracking-wider font-medium"
<th >{{ $t('distance') }}</th>
class="px-4 py-3 title-font tracking-wider font-medium" <th
>{{ $t('lap_time') }}</th> class="px-4 py-3 title-font tracking-wider font-medium"
</tr> >{{ $t('lap_time') }}</th>
</thead> </tr>
<tbody class="text-gray-900 dark:text-gray-50"> </thead>
<tr v-for="s in state.scans" :key="s.id"> <tbody class="text-gray-900 dark:text-gray-50">
<td class="px-4 py-3"> <tr v-for="s in state.scans" :key="s.id">
<span v-text="s.distance"></span>m <td class="px-4 py-3">
</td> <span v-text="s.distance"></span>
<td class="px-4 py-3" v-text="s.lapTime"></td> </td>
</tr> <td class="px-4 py-3" v-text="s.lapTime"></td>
</tbody> </tr>
</table> </tbody>
<div v-else class="text-center font-bold text-black dark:text-white text-2xl"> </table>
<img <div v-else class="text-center font-bold text-black dark:text-white text-2xl">
src="../assets/empty_laps.svg" <img
style="height:25rem; margin:0 auto;" src="../assets/empty_laps.svg"
:alt="[[$t('no_laps_scans_were_recorded_yet')]]" style="height:25rem; margin:0 auto;"
/> :alt="[[$t('no_laps_scans_were_recorded_yet')]]"
{{ $t('no_laps_scans_were_recorded_yet') }} />
</div> {{ $t('no_laps_scans_were_recorded_yet') }}
</div> </div>
</div> </div>
</section> </div>
</div> </section>
</div> </div>
<div v-if="(state.activetab === 'sponsorings')" class="tab-content block"> </div>
<div class="py-4 w-full">coming soon...</div> <div v-if="(state.activetab === 'sponsorings')" class="tab-content block">
</div> <div class="py-4 w-full">
</div> <section class="text-gray-400 dark:bg-gray-900 body-font">
</div> <div class="container mx-auto">
</div> <div class="lg:w-2/3 w-full mx-auto overflow-auto">
</div> <table
</template> v-if="state.sponsorings.length > 0"
class="table-auto w-full text-left whitespace-no-wrap"
<script setup> >
import { reactive } from "vue"; <thead
import { useToast } from "vue-toastification"; class="text-black bg-gray-300 dark:text-white text-sm dark:bg-gray-800"
import axios from "redaxios"; >
<tr>
const state = reactive({ <th class="px-4 py-3 title-font tracking-wider font-medium">Name</th>
phone: "", <th
email: "", class="px-4 py-3 title-font tracking-wider font-medium"
firstname: "", >{{ $t('amount_per_kilometer_in_eur') }}</th>
middlename: "", <th
lastname: "", class="px-4 py-3 title-font tracking-wider font-medium"
scans: [], >{{ $t('current_total_amount_in_eur') }}</th>
group: "", </tr>
activetab: "profile", </thead>
delete_active: false, <tbody class="text-gray-900 dark:text-gray-50">
}) <tr v-for="s in state.sponsorings" :key="s.id">
const toast = useToast(); <td class="px-4 py-3">
const props = defineProps({ <span v-text="s.donor.firstname"></span>
token: String <span v-if="s.donor.middlename">
}) <span v-text="s.donor.middlename"></span>
const accesstoken = atob(props.token); </span>
axios.get(`${config.baseurl}api/runners/me/${accesstoken}`) <span v-text="s.donor.lastname"></span>
.then(({ data }) => { </td>
state.phone = data.phone; <td class="px-4 py-3">
state.email = data.email; <span
state.firstname = data.firstname; v-text="(s.amountPerDistance / 100)
state.middlename = data.middlename; .toFixed(2)
state.lastname = data.lastname; .toLocaleString('de-DE', { valute: 'EUR' })"
state.group = data.group; ></span>€
}).catch((error) => { </td>
toast.error("An error occured while loading your profile data"); <td class="px-4 py-3">
}) <span
axios.get(`${config.baseurl}api/runners/me/${accesstoken}/scans`) v-text="(s.amount / 100)
.then(({ data }) => { .toFixed(2)
data.map(function(s) { .toLocaleString('de-DE', { valute: 'EUR' })"
s.lapTime = Math.floor(s.lapTime / 60) + 'min ' + (Math.floor(s.lapTime % 60) + "").padStart(2, "0") + "s" ></span>€
return s; </td>
}) </tr>
data.filter(s => s.valid === true); </tbody>
state.scans = data; <tfoot class="text-gray-900 dark:text-gray-50">
}).catch((error) => { <tr>
toast.error("An error occured while loading your profile data"); <td class="px-4 py-3">{{ $t('total') }}</td>
}) <td class="px-4 py-3">
function delete_me() { <span
toast("Deletion in progress..."); v-text="(state.sponsorings.reduce(function(sum, current) {
let url = `${config.baseurl}api/runners/me/${accesstoken}?force=true` return sum + current.amountPerDistance;
axios.delete(url) }, 0) / 100)
.then(() => { .toFixed(2)
toast("All Data deleted!"); .toLocaleString('de-DE', { valute: 'EUR' })"
location.replace(`${config.baseurl_selfservice}`); ></span>€
}) </td>
.catch((error) => { <td class="px-4 py-3">
toast.error("An error occured while deleting your profile data"); <span
}); v-text="(state.sponsorings.reduce(function(sum, current) {
} return sum + current.amount;
}, 0) / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })"
></span>€
</td>
</tr>
</tfoot>
</table>
<div v-else class="text-center font-bold text-black dark:text-white text-2xl">
<img
src="../assets/empty_laps.svg"
style="height:25rem; margin:0 auto;"
:alt="[[$t('no_sponsorings_for_you_were_recorded_yet')]]"
/>
{{ $t('no_sponsorings_for_you_were_recorded_yet') }}
</div>
</div>
</div>
</section>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { reactive } from "vue";
import { useToast } from "vue-toastification";
import axios from "redaxios";
const state = reactive({
phone: "",
email: "",
firstname: "",
middlename: "",
lastname: "",
scans: [],
sponsorings: [],
group: "",
activetab: "profile",
delete_active: false,
fullobject: {}
})
const toast = useToast();
const props = defineProps({
token: String
})
const accesstoken = atob(props.token);
axios.get(`${config.baseurl}api/runners/me/${accesstoken}`)
.then(({ data }) => {
state.phone = data.phone;
state.email = data.email;
state.firstname = data.firstname;
state.middlename = data.middlename;
state.lastname = data.lastname;
state.group = data.group;
state.sponsorings = data.distanceDonations;
state.fullobject = data;
}).catch((error) => {
toast.error("An error occured while loading your profile data");
})
axios.get(`${config.baseurl}api/runners/me/${accesstoken}/scans`)
.then(({ data }) => {
data.map(function(s) {
s.lapTime = Math.floor(s.lapTime / 60) + 'min ' + (Math.floor(s.lapTime % 60) + "").padStart(2, "0") + "s"
s.distance = Math.floor(s.distance / 1000) + 'km ' + (Math.floor(s.distance % 1000) + "").padStart(3, "0") + "m"
return s;
})
data.filter(s => s.valid === true);
state.scans = data;
}).catch((error) => {
toast.error("An error occured while loading your profile data");
})
function delete_me() {
toast("Deletion in progress...");
let url = `${config.baseurl}api/runners/me/${accesstoken}?force=true`
axios.delete(url)
.then(() => {
toast("All Data deleted!");
location.replace(`${config.baseurl_selfservice}`);
})
.catch((error) => {
toast.error("An error occured while deleting your profile data");
});
}
function get_certificate() {
toast("Generation in progress...");
const browserlocale = ((navigator.languages && navigator.languages[0]) || '').substr(0, 2);
let url = `${config.baseurl}documents/certificates?locale=${browserlocale}&download=true&key=${config.documentserver_key}`;
let postdata = Object.assign({}, state.fullobject);
postdata.group = {
name: postdata.group
}
postdata = [postdata]
axios.post(url, postdata, {
responseType: "blob"
})
.then((response) => {
console.log(response)
if (response.status != "200") {
toast.error("An error occured while generateing your certificate!");
} else {
var fileURL = window.URL.createObjectURL(new Blob([response.data], { type: 'application/pdf' }));
var fileLink = document.createElement('a');
fileLink.href = fileURL;
fileLink.setAttribute('download', 'Certificate.pdf');
document.body.appendChild(fileLink);
fileLink.click();
fileLink.remove();
toast("Document generated!");
}
})
.catch((err) => {
console.error(err);
toast.error("An error occured while deleting your profile data");
});
}
</script> </script>