Compare commits

..

5 Commits
1.2.6 ... main

Author SHA1 Message Date
00a0c99f70
Merge branch 'dev'
All checks were successful
ci/woodpecker/push/build Pipeline was successful
2024-12-02 16:49:36 +01:00
8fb39276af
chore: 2025 2024-11-21 10:48:22 +01:00
a1b600df1c
Merge branch 'dev'
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-03 13:54:34 +01:00
fe1bbc7816
Merge branch 'dev'
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-02 00:21:22 +01:00
7ae0081d69 Merge pull request 'sync - 0.4.5' (#34) from dev into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #34
2021-04-01 16:46:05 +00:00
20 changed files with 1867 additions and 1832 deletions

View File

@ -2,105 +2,9 @@
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.6](https://git.odit.services/lfk/selfservice/compare/1.2.5...1.2.6)
- fix(profile): font sizes [`c98a65d`](https://git.odit.services/lfk/selfservice/commit/c98a65d918e5d652ee98044b4d5333c7000e1c87)
#### [1.2.5](https://git.odit.services/lfk/selfservice/compare/1.2.4...1.2.5)
> 18 March 2025
- refactor: move to new lfk ts client [`865058c`](https://git.odit.services/lfk/selfservice/commit/865058c8bb7eec03278bf1f4a7b708429d0b5b20)
- feat: cleanup [`b3197dd`](https://git.odit.services/lfk/selfservice/commit/b3197dd3f95cd7d222f1ea168e9826f7ad7ef903)
- refactor: simplify imprint + privacy [`50fbfe0`](https://git.odit.services/lfk/selfservice/commit/50fbfe05f1ba830ea19f9e86b7a2fdce588f1a31)
- feat: improved tabs [`51b66eb`](https://git.odit.services/lfk/selfservice/commit/51b66eb85b3003996ac2414757ae62ee7ba80ce5)
- fix(register): phone number verification [`d5eefbb`](https://git.odit.services/lfk/selfservice/commit/d5eefbb5e22f4cc7b50e1f0c469779d3b7e310f5)
- feat: improved icons [`9af9c89`](https://git.odit.services/lfk/selfservice/commit/9af9c897f17b8a1be12f47dc271382629fc298ff)
- feat: profile cleanup [`d50719c`](https://git.odit.services/lfk/selfservice/commit/d50719c0dad4e3fbf008fb240edff80c4ea6ab4c)
- 🚀Bumped version to v1.2.5 [`b1ab04f`](https://git.odit.services/lfk/selfservice/commit/b1ab04fa53817178e016d7c2c387db12c0f6a987)
- register: drop middlename [`d503061`](https://git.odit.services/lfk/selfservice/commit/d5030616043fb9fa4eccc7894ee3ada92928d102)
- feat: profile cleanup [`03532cc`](https://git.odit.services/lfk/selfservice/commit/03532cc365e38d7313ff2e8571ae15975d8a53e5)
- feat: cleanup [`0ff6df6`](https://git.odit.services/lfk/selfservice/commit/0ff6df68d61404c7be7a1e9b88a354fb12ce0907)
#### [1.2.4](https://git.odit.services/lfk/selfservice/compare/1.2.3...1.2.4)
> 17 March 2025
- feat: loading screen [`2939911`](https://git.odit.services/lfk/selfservice/commit/2939911c993c3817d841d4cb4660aa940e478cc0)
- 🚀Bumped version to v1.2.4 [`f1d552c`](https://git.odit.services/lfk/selfservice/commit/f1d552ce64557b5da0dea91e114d3ebf2f8f0199)
#### [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.4.0-alpine3.20 AS build FROM node:23.3.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,6 +7,7 @@ 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

6
env_fix.js Normal file
View File

@ -0,0 +1,6 @@
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,20 @@
{ {
"name": "@odit/lfk-selfservice", "name": "@odit/lfk-selfservice",
"version": "1.2.6", "version": "1.0.1",
"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.2.5", "@fontsource/athiti": "^5.1.0",
"@odit/lfk-client": "^0.0.1", "@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.14", "tailwindcss": "4.0.0-beta.4",
"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 +23,11 @@
"vue-toastification": "2.0.0-rc.1" "vue-toastification": "2.0.0-rc.1"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "5.2.3", "@vitejs/plugin-vue": "5.2.1",
"autoprefixer": "10.4.21", "autoprefixer": "10.4.20",
"release-it": "18.1.2", "release-it": "17.10.0",
"vite": "6.2.2", "vite": "6.0.2",
"vite-plugin-vue-devtools": "7.7.2" "vite-plugin-vue-devtools": "^7.6.7"
}, },
"release-it": { "release-it": {
"git": { "git": {

2342
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,14 @@
const config = { const config = {
// required // required
documentserver_key: "", documentserver_key: '',
// required, with trailing slash // required, with trailing slash
baseurl: "", baseurl: '',
// optional, full url, will fallback to https://lauf-fuer-kaya.de/impressum
url_imprint: "",
// optional, full url, will fallback to https://lauf-fuer-kaya.de/datenschutz
url_privacy: "",
// full url (including fqdn) // full url (including fqdn)
baseurl_documentserver: "http://localhost:3000", baseurl_documentserver: 'http://localhost:4010/documents',
// optional, will fallback to code128 // optional, will fallback to code128
code_format: "ean13", code_format: 'ean13',
// optional, will fallback to /imprint
url_imprint: '',
// optional, will fallback to /privacy
url_privacy: '',
}; };

1
public/imprint_en.md Normal file
View File

@ -0,0 +1 @@
TODO:

1
public/privacy_en.md Normal file
View File

@ -0,0 +1 @@
TODO:

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -1,15 +1,15 @@
<template> <template>
<footer> <footer>
<div class="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 sm:py-2 sm:mt-0 mt-4 text-center md:text-left"> <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">
Lauf für Kaya! Selfservice<br>Copyright © 2025<br>proudly powered by Lauf für Kaya! Selfservice<br>Copyright © 2024<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 underline">{{ <a target="_blank" rel="noopener,noreferrer" :href="[[imprint_url]]" class="ml-3 text-gray-400 underline">{{
$t('imprint') }}</a> $t('imprint') }}</a>
<a target="_blank" rel="noopener,noreferrer" :href="[[privacy_url]]" class="ml-3 underline">{{ <a target="_blank" rel="noopener,noreferrer" :href="[[privacy_url]]" class="ml-3 text-gray-400 underline">{{
$t('privacy_policy') }}</a> $t('privacy_policy') }}</a>
</span> </span>
</div> </div>
@ -19,8 +19,8 @@
export default { export default {
data() { data() {
return { return {
imprint_url: config.url_imprint || "https://lauf-fuer-kaya.de/impressum" imprint_url: config.url_imprint || "/imprint"
, privacy_url: config.url_privacy || "https://lauf-fuer-kaya.de/datenschutz" , privacy_url: config.url_privacy || "/privacy"
} }
}, },
} }

View File

@ -1,6 +1,5 @@
{ {
"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 €)",
@ -16,9 +15,9 @@
"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_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.",
@ -32,8 +31,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",
"nachname_des_sponsors": "Nachname des Sponsors", "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",
@ -60,20 +58,14 @@
"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,6 +1,5 @@
{ {
"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 €)",
@ -16,9 +15,9 @@
"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_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.",
@ -32,7 +31,6 @@
"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?",
@ -60,20 +58,14 @@
"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,13 +1,19 @@
import Home from "./views/Home.vue"; import Home from "./views/Home.vue";
import Imprint from "./views/Imprint.vue";
import Privacy from "./views/Privacy.vue";
import Register from "./views/Register.vue"; import Register from "./views/Register.vue";
import Profile from "./views/Profile.vue"; import Profile from "./views/Profile.vue";
import ProfileNone from "./views/ProfileNone.vue"; import ProfileNone from "./views/ProfileNone.vue";
// console.log(config); console.log(config);
/** @type {import('vue-router').RouterOptions['routes']} */ /** @type {import('vue-router').RouterOptions['routes']} */
export const routes = [ export const routes = [
{ path: "/", component: Home }, { path: "/", component: Home },
{ path: "/imprint", component: Imprint },
{ path: "/imprint/", component: Imprint },
{ path: "/privacy", component: Privacy },
{ path: "/privacy/", component: Privacy },
{ path: "/register", component: Register }, { path: "/register", component: Register },
{ path: "/register/", component: Register }, { path: "/register/", component: Register },
{ path: "/register/:token", component: Register, props: true }, { path: "/register/:token", component: Register, props: true },

View File

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

View File

@ -1,13 +1,13 @@
<template> <template>
<div class="bg-cover bg-fixed m-0 h-screen text-white" <div class="bg-cover bg-fixed m-0 h-screen text-white"
v-bind:style='{ backgroundImage: "url(" + background_base64 + ")", }'> v-bind:style='{ backgroundImage: "url(" + background_base64 + ")", }'>
<section class="px-4 py-24 mx-auto"> <section class="container px-4 py-24 mx-auto">
<div class="w-full mx-auto text-center"> <div class="w-full mx-auto text-center">
<img src="/favicon-lfk.png" class="h-32 mx-auto" /> <img src="/favicon-lfk.png" class="h-32 mx-auto" />
<h1 <h1
class="mb-6 text-4xl font-extrabold leading-none tracking-normal md:text-6xl md:tracking-tight"> class="mb-6 text-4xl font-extrabold leading-none tracking-normal md:text-6xl md:tracking-tight font-[Athiti]">
Lauf Für Kaya!<br>2025</h1> Lauf Für Kaya!<br>2025</h1>
<h2 class="mb-6 text-xl font-bold leading-none tracking-normal md:text-3xl md:tracking-tight"> <h2 class="mb-6 text-xl font-bold leading-none tracking-normal md:text-3xl md:tracking-tight font-[Athiti]">
Selfservice Portal</h2> Selfservice Portal</h2>
<p class="px-0 mb-6 text-md lg:px-24 font-medium">{{ $t('main_page_text') }}</p> <p class="px-0 mb-6 text-md lg:px-24 font-medium">{{ $t('main_page_text') }}</p>
<a class="w-full block mx-auto md:w-3/4 px-6 py-3 border border-transparent text-base font-semibold rounded-md text-gray-900 bg-white shadow-sm hover:text-gray-600 focus:outline-none focus:text-gray-600 xl:text-lg xl:py-4" <a class="w-full block mx-auto md:w-3/4 px-6 py-3 border border-transparent text-base font-semibold rounded-md text-gray-900 bg-white shadow-sm hover:text-gray-600 focus:outline-none focus:text-gray-600 xl:text-lg xl:py-4"

40
src/views/Imprint.vue Normal file
View File

@ -0,0 +1,40 @@
<template>
<section class="container px-4 py-24 mx-auto">
<div class="simplecontent">
<div class="mb-24 text-left md:text-center">
<h1 class="mb-4 text-4xl font-bold leading-tight text-gray-900 dark:text-gray-50 md:text-5xl">{{ $t('imprint')
}}
</h1>
</div>
<div class="mx-auto prose" v-html="content"></div>
</div>
</section>
<Footer></Footer>
</template>
<style src="../simple.css"></style>
<script>
import { marked } from "marked";
import Footer from "@/components/Footer.vue";
export default {
components: { Footer },
data() {
return {
content: "",
}
},
async beforeMount() {
const browserlocale = ((navigator.languages && navigator.languages[0]) || '').substr(0, 2);
let md = "";
try {
md = await fetch(`/imprint_${browserlocale}.md`);
} catch (error) {
try {
md = await fetch(`/imprint_en.md`);
} catch (error) {
md = t('error_loading_imprint');
}
}
this.content = marked(await md.text());
},
}
</script>

39
src/views/Privacy.vue Normal file
View File

@ -0,0 +1,39 @@
<template>
<section class="container px-4 py-24 mx-auto">
<div class="simplecontent">
<div class="mb-24 text-left md:text-center">
<h1 class="mb-4 text-4xl font-bold leading-tight text-gray-900 dark:text-gray-50 md:text-5xl">{{
$t('privacy_policy') }}</h1>
</div>
<div class="mx-auto prose" v-html="content"></div>
</div>
</section>
<Footer></Footer>
</template>
<style src="../simple.css"></style>
<script>
import { marked } from "marked";
import Footer from "@/components/Footer.vue";
export default {
components: { Footer },
data() {
return {
content: ""
}
},
async beforeMount() {
const browserlocale = ((navigator.languages && navigator.languages[0]) || '').substr(0, 2);
let md = "";
try {
md = await fetch(`/privacy_${browserlocale}.md`);
} catch (error) {
try {
md = await fetch(`/privacy_en.md`);
} catch (error) {
md = t('error-loading-privacy-policy');
}
}
this.content = marked(await md.text());
},
}
</script>

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
<div class="min-h-screen flex items-center justify-center"> <div class="min-h-screen flex items-center justify-center">
<div class="max-w-md w-full py-12 px-6"> <div class="max-w-md w-full py-12 px-6">
<img class="mx-auto h-24 w-auto" src="/favicon-lfk.png" alt /> <img class="mx-auto h-24 w-auto" src="/favicon-lfk.png" alt />
<h1 class="sm:text-3xl text-2xl font-semibold title-font mb-4 text-center">Lauf für Kaya! - {{ <h1 class="sm:text-3xl text-2xl font-semibold title-font mb-4 text-center font-[Athiti]">Lauf für Kaya! - {{
$t('profile') $t('profile')
}}</h1> }}</h1>
<p class="mx-auto leading-relaxed text-base text-center"> <p class="mx-auto leading-relaxed text-base text-center">
@ -59,12 +59,12 @@
</template> </template>
<script setup> <script setup>
import Footer from "@/components/Footer.vue"; import { computed, ref, reactive } from "vue";
import { runnerSelfServiceControllerRequestNewToken } from "@odit/lfk-client"; import axios from "redaxios";
import isEmail from 'validator/es/lib/isEmail'; import isEmail from 'validator/es/lib/isEmail';
import { computed, reactive, ref } from "vue";
import { useI18n } from 'vue-i18n';
import { TYPE, useToast } from "vue-toastification"; import { TYPE, useToast } from "vue-toastification";
import Footer from "@/components/Footer.vue";
import { useI18n } from 'vue-i18n'
const { t } = useI18n() const { t } = useI18n()
let user_email = ref(""); let user_email = ref("");
@ -79,10 +79,11 @@ function resendMail() {
if (isEmail(user_email.value)) { if (isEmail(user_email.value)) {
toast(t('login_link_is_requested')); toast(t('login_link_is_requested'));
const browserlocale = ((navigator.languages && navigator.languages[0]) || '').substr(0, 2); const browserlocale = ((navigator.languages && navigator.languages[0]) || '').substr(0, 2);
runnerSelfServiceControllerRequestNewToken({ query: { locale: browserlocale, mail: user_email.value } }).then(({ data }) => { axios.post(`${config.baseurl}api/runners/login?mail=${user_email.value}&locale=${browserlocale}`)
console.log(data); .then(({ data }) => {
toast(t('login_link_gesendet_an_user_email_value') + user_email.value); console.log(data);
}) toast(t('login_link_gesendet_an_user_email_value') + user_email.value);
})
.catch((error) => { .catch((error) => {
console.log(error); console.log(error);
toast(t('error_requesting_the_login_link'), { type: TYPE.ERROR }); toast(t('error_requesting_the_login_link'), { type: TYPE.ERROR });

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="min-h-screen flex items-center justify-center" v-if="registrationState === 'registered'"> <div class="min-h-screen flex items-center justify-center" v-if="registrationState === 'registered'">
<div class="max-w-md w-full py-12 px-6"> <div class="max-w-md w-full py-12 px-6 font-[Athiti]">
<img class="mx-auto h-24 w-auto" src="/favicon-lfk.png" alt /> <img class="mx-auto h-24 w-auto" src="/favicon-lfk.png" alt />
<h1 class="sm:text-3xl text-2xl font-semibold title-font mb-4 text-center"> <h1 class="sm:text-3xl text-2xl font-semibold title-font mb-4 text-center">
Lauf für Kaya! - {{ $t('registriert') }} Lauf für Kaya! - {{ $t('registriert') }}
@ -12,7 +12,7 @@
</div> </div>
</div> </div>
<div class="min-h-screen flex items-center justify-center" v-else> <div class="min-h-screen flex items-center justify-center" v-else>
<div class="max-w-md w-full py-12 px-6"> <div class="max-w-md w-full py-12 px-6 font-[Athiti]">
<img class="mx-auto h-24 w-auto" src="/favicon-lfk.png" alt /> <img class="mx-auto h-24 w-auto" src="/favicon-lfk.png" alt />
<h1 class="sm:text-3xl text-2xl font-semibold title-font mb-4 text-center"> <h1 class="sm:text-3xl text-2xl font-semibold title-font mb-4 text-center">
Lauf für Kaya! - {{ $t("registrieren") }} Lauf für Kaya! - {{ $t("registrieren") }}
@ -73,6 +73,24 @@
p-2 p-2
" /> " />
<!-- --> <!-- -->
<label for="middle_name" class="block font-medium">{{
$t("mittelname")
}}</label>
<input v-model="userdetails.middlename" name="middlename" id="middle_name" autocomplete="off"
:placeholder="[[$t('mittelname')]]" type="text" class="
dark:bg-gray-800
mt-1
block
w-full
shadow-sm
sm:text-sm
border-gray-300 border-2
bg-gray-50
text-gray-500
rounded-md
p-2
" />
<!-- -->
<label for="last_name" class="block font-medium"> <label for="last_name" class="block font-medium">
{{ $t("nachname") }} {{ $t("nachname") }}
<span class="font-bold">*</span> <span class="font-bold">*</span>
@ -126,9 +144,9 @@
<input v-model="userdetails.phone" name="phone" id="phone" autocomplete="off" <input v-model="userdetails.phone" name="phone" id="phone" autocomplete="off"
:placeholder="[[$t('phone_number')]]" type="text" :class="{ :placeholder="[[$t('phone_number')]]" type="text" :class="{
'border-red-500': 'border-red-500':
!isPhoneOkay(userdetails.phone), !isMobilePhone(userdetails.phone) && userdetails.phone.trim(),
'border-green-300': 'border-green-300':
isPhoneOkay(userdetails.phone), isMobilePhone(userdetails.phone) && userdetails.phone.trim(),
}" class=" }" class="
dark:bg-gray-800 dark:bg-gray-800
mt-1 mt-1
@ -142,7 +160,7 @@
rounded-md rounded-md
p-2 p-2
" /> " />
<p v-if="!isPhoneOkay(userdetails.phone)" class="text-sm"> <p v-if="!isMobilePhone(userdetails.phone) && userdetails.phone.trim()" class="text-sm">
{{ $t("this_is_not_a_valid_international_phone_number") }} {{ $t("this_is_not_a_valid_international_phone_number") }}
</p> </p>
<!-- --> <!-- -->
@ -155,7 +173,7 @@
</div> </div>
<div class="ml-3 text-sm"> <div class="ml-3 text-sm">
<label for="address_activated" class="font-medium text-gray-600 select-none">{{ $t("provide_address") <label for="address_activated" class="font-medium text-gray-600 select-none">{{ $t("provide_address")
}}</label> }}</label>
</div> </div>
</div> </div>
<div v-if="provide_address === true" class="col-span-6"> <div v-if="provide_address === true" class="col-span-6">
@ -317,24 +335,27 @@
</template> </template>
<script setup> <script setup>
import Footer from "@/components/Footer.vue"; import { computed, ref, reactive } from "vue";
import { runnerSelfServiceControllerGetSelfserviceOrg, runnerSelfServiceControllerRegisterOrganizationRunner, runnerSelfServiceControllerRegisterRunner } from "@odit/lfk-client"; import axios from "redaxios";
import isEmail from "validator/es/lib/isEmail"; import isEmail from "validator/es/lib/isEmail";
import isMobilePhone from "validator/es/lib/isMobilePhone"; import isMobilePhone from "validator/es/lib/isMobilePhone";
import isPostalCode from "validator/es/lib/isPostalCode"; import isPostalCode from "validator/es/lib/isPostalCode";
import { computed, reactive, ref } from "vue";
import { useI18n } from 'vue-i18n';
import { TYPE, useToast } from "vue-toastification"; import { TYPE, useToast } from "vue-toastification";
import Footer from "@/components/Footer.vue";
import { useI18n } from 'vue-i18n'
const { t } = useI18n() const { t } = useI18n()
const props = defineProps({ const props = defineProps({
token: String, token: String,
}); });
if (props.token) { if (props.token) {
runnerSelfServiceControllerGetSelfserviceOrg({ path: { token: props.token } }).then(({ data }) => { axios
state.org_name = data.name; .get(`${config.baseurl}api/organizations/selfservice/${props.token}`)
state.org_teams = data.teams; .then(({ data }) => {
org_team.value = data.teams[0]?.id; state.org_name = data.name;
}) state.org_teams = data.teams;
org_team.value = data.teams[0]?.id;
})
.catch((error) => { .catch((error) => {
console.log(error); console.log(error);
}); });
@ -348,21 +369,6 @@ let userdetails = ref({
phone: "", phone: "",
address: { street: "", address2: "", city: "", zipcode: "" }, address: { street: "", address2: "", city: "", zipcode: "" },
}); });
function isPhoneOkay() {
if (userdetails.value.phone === "") {
return true
}
if (userdetails.value.phone.includes(" ")) {
return false
}
if (!userdetails.value.phone.includes("+")) {
return false
}
if (isMobilePhone(userdetails.value.phone)) {
return true
}
return false
}
let provide_address = ref(false); let provide_address = ref(false);
let agb_accepted = ref(false); let agb_accepted = ref(false);
let data_confirmed = ref(false); let data_confirmed = ref(false);
@ -376,7 +382,8 @@ const state = reactive({
() => () =>
agb_accepted.value === true && agb_accepted.value === true &&
data_confirmed.value === true && data_confirmed.value === true &&
isPhoneOkay() && (isMobilePhone(userdetails.value.phone) ||
!userdetails.value.phone.trim()) &&
isEmail(userdetails.value.mail) && isEmail(userdetails.value.mail) &&
userdetails.value.firstname && userdetails.value.firstname &&
userdetails.value.lastname && userdetails.value.lastname &&
@ -389,25 +396,25 @@ const state = reactive({
}); });
const toast = useToast(); const toast = useToast();
function login() { function login() {
// userdetails = userdetails.value; userdetails = userdetails.value;
if (isPhoneOkay()) { if (userdetails?.phone === "" || isMobilePhone(userdetails.phone)) {
if (isEmail(userdetails.value.mail)) { if (isEmail(userdetails.mail)) {
let postdata = { let postdata = {
email: userdetails.value.mail, email: userdetails.mail,
firstname: userdetails.value.firstname, firstname: userdetails.firstname,
middlename: userdetails.value.middlename, middlename: userdetails.middlename,
lastname: userdetails.value.lastname, lastname: userdetails.lastname,
address: {}, address: {},
}; };
if (userdetails.value.phone !== "") { if (isMobilePhone(userdetails.phone)) {
postdata.phone = userdetails.value.phone postdata.phone = userdetails.phone;
} }
if (provide_address.value === true) { if (provide_address.value === true) {
postdata.address = { postdata.address = {
address1: userdetails.value.address.street, address1: userdetails.address.street,
address2: userdetails.value.address.address2 || "", address2: userdetails.address.address2 || "",
city: userdetails.value.address.city, city: userdetails.address.city,
postalcode: userdetails.value.address.zipcode, postalcode: userdetails.address.zipcode,
country: "DE", country: "DE",
}; };
} }
@ -419,42 +426,28 @@ function login() {
(navigator.languages && navigator.languages[0]) || (navigator.languages && navigator.languages[0]) ||
"" ""
).substr(0, 2); ).substr(0, 2);
registrationState.value = "loading"; let url = `${config.baseurl}api/runners/register/?locale=${browserlocale}`;
if (props.token) { if (props.token) {
runnerSelfServiceControllerRegisterOrganizationRunner({ path: { token: props.token }, body: postdata, query: { locale: browserlocale } }) url = `${config.baseurl}api/runners/register/${props.token}/?locale=${browserlocale}`;
.then(() => {
registrationState.value = "registered";
})
.catch((error) => {
console.log(error);
if (error.data.message === "E-Mail already registered") {
toast(t('already_registered'), { type: TYPE.ERROR });
} else if (error.data.message === "Invalid body, check 'errors' property for more info.") {
error.data.errors.forEach(e => {
if (e.property === "phone") {
toast(t('invalid_input_phone_number_should_be_international_format'), { type: TYPE.ERROR });
}
});
}
});
} else {
runnerSelfServiceControllerRegisterRunner({ body: postdata, query: { locale: browserlocale } })
.then(() => {
registrationState.value = "registered";
})
.catch((error) => {
console.log(error);
if (error.data.message === "E-Mail already registered") {
toast(t('already_registered'), { type: TYPE.ERROR });
} else if (error.data.message === "Invalid body, check 'errors' property for more info.") {
error.data.errors.forEach(e => {
if (e.property === "phone") {
toast(t('invalid_input_phone_number_should_be_international_format'), { type: TYPE.ERROR });
}
});
}
});
} }
registrationState.value = "loading";
axios
.post(url, postdata)
.then(() => {
registrationState.value = "registered";
})
.catch((error) => {
console.log(error);
if (error.data.message === "E-Mail already registered") {
toast(t('already_registered'), { type: TYPE.ERROR });
} else if (error.data.message === "Invalid body, check 'errors' property for more info.") {
error.data.errors.forEach(e => {
if (e.property === "phone") {
toast(t('invalid_input_phone_number_should_be_international_format'), { type: TYPE.ERROR });
}
});
}
});
} }
} }
} }