Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • Teckids/hacknfun/AlekSIS-App-Paweljong
  • 8sercomcurro/AlekSIS-App-Paweljong
  • gassungtholbuy/AlekSIS-App-Paweljong
  • inturnickterc/AlekSIS-App-Paweljong
  • 3vibbergulyo/AlekSIS-App-Paweljong
  • 9fulcvoZdendmi/AlekSIS-App-Paweljong
  • 8stagitWriate/AlekSIS-App-Paweljong
  • 9sorneWpersma/AlekSIS-App-Paweljong
  • imelKgeshi/AlekSIS-App-Paweljong
  • ceotremagi/AlekSIS-App-Paweljong
  • niebutdiscchi/AlekSIS-App-Paweljong
  • plusultesetz/AlekSIS-App-Paweljong
  • 7tiadeKplicpu/AlekSIS-App-Paweljong
  • grehanbeci/AlekSIS-App-Paweljong
  • inocpuhaw/AlekSIS-App-Paweljong
  • 7inenprobko/AlekSIS-App-Paweljong
  • _weblate/AlekSIS-App-Paweljong
17 results
Show changes
Commits on Source (272)
Showing
with 3604 additions and 440 deletions
{
"name": "aleksis-builddeps",
"version": "1.0.0",
"dependencies": {
"@intlify/eslint-plugin-vue-i18n": "^2.0.0",
"eslint": "^8.26.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-vue": "^9.7.0",
"prettier": "^3.0.0",
"stylelint": "^15.0.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^34.0.0"
}
}
......@@ -52,6 +52,11 @@ DEADJOE
.idea
.idea/
# VSCode
.vscode/
.history/
*.code-workspace
# Database
db.sqlite3
......@@ -62,20 +67,28 @@ docs/_build/
*.aux
# Generated files
aleksis/node_modules/
aleksis/static/
aleksis/whoosh_index/
/cache
/node_modules
.dev-js/node_modules
/static/
/whoosh_index/
.vite
.dev-js/.yarn
.dev-js/.pnp.cjs
.dev-js/.pnp.loader.mjs
# Lock files
poetry.lock
package-lock.json
yarn.lock
.dev-js/yarn.lock
# Tests
.coverage
.mypy_cache/
.tox/
htmlcov/
# Data
maintenance_mode_state.txt
media/
package-lock.json
# VSCode
.vscode/
.history/
*.code-workspace
include:
- project: "AlekSIS/official/AlekSIS"
file: /ci/general.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/prepare/lock.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/lint.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/security.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/build/dist.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/docker/dist.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/general.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/prepare/lock.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/security.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/build/dist.yml
variables:
GIT_SUBMODULE_STRATEGY: recursive
......@@ -26,11 +22,11 @@ deploy_gitlab:
stage: publish
script:
- if [ x$CI_COMMIT_REF_NAME = x$CI_COMMIT_TAG ]; then
if ! [ "$(poetry version | cut -d" " -f2)" = $CI_COMMIT_REF_NAME ]; then
echo "Package version does not match tag. Aborting build of tag!" >/dev/fd/2 ;
exit 1 ;
fi ;
if ! [ "$(poetry version | cut -d" " -f2)" = $CI_COMMIT_REF_NAME ]; then
echo "Package version does not match tag. Aborting build of tag!" >/dev/fd/2 ;
exit 1 ;
fi ;
else
poetry version $(poetry version | cut -d" " -f2)+$(date --date=${CI_COMMIT_TIMESTAMP} +%Y%m%d%H%M%S).${CI_COMMIT_SHORT_SHA} ;
poetry version $(poetry version | cut -d" " -f2)+$(date --date=${CI_COMMIT_TIMESTAMP} +%Y%m%d%H%M%S).${CI_COMMIT_SHORT_SHA} ;
fi
- poetry publish -r gitlab
# Byte-compiled / optimized / DLL files
*$py.class
*.py[cod]
__pycache__/
# Distribution / packaging
*.egg
*.egg-info/
.Python
.eggs/
.installed.cfg
build/
develop-eggs/
dist/
downloads/
eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
# Installer logs
pip-delete-this-directory.txt
pip-log.txt
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# pyenv
.python-version
# Environments
.env
.venv
ENV/
env/
venv/
# Editors
*~
DEADJOE
\#*#
# IntelliJ
.idea
.idea/
# Database
db.sqlite3
# Sphinx
docs/_build/
# TeX
*.aux
# Generated files
/node_modules/
/static/
/whoosh_index/
poetry.lock
.coverage
.mypy_cache/
.tox/
htmlcov/
maintenance_mode_state.txt
media/
package-lock.json
yarn.lock
# VSCode
.vscode/
.history/
*.code-workspace
/cache
# Add HTML files to avoid problems with unsupported Django templates
*.html
# Do not check/reformat generated files
aleksis/core/util/licenses.json
.vite/
.pnp.cjs
.pnp.loader.mjs
......@@ -6,6 +6,14 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog`_,
and this project adheres to `Semantic Versioning`_.
Unreleased
----------
Added
~~~~~
* Add SPA support for AlekSIS-Core 3.0
`1.5.1`_
--------
......
......@@ -29,7 +29,7 @@ class EventMembersSyncDataCheck(DataCheck):
async_events = []
for event in Event.objects.all():
if not set(event.linked_group.members.values_list("id", flat=True)) == set(
if set(event.linked_group.members.values_list("id", flat=True)) != set(
event.registrations.filter(retracted=False).values_list("person", flat=True)
):
async_events.append(event)
......
from django import forms
from django.forms import fields
from django.forms import fields, widgets
from django.utils import dateformat, formats
from django.utils.translation import gettext_lazy as _
......@@ -8,6 +8,7 @@ from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget
from material import Fieldset, Layout, Row
from phonenumber_field.formfields import PhoneNumberField
from aleksis.apps.tezor.models.base import Client
from aleksis.apps.tezor.models.invoice import InvoiceGroup
from aleksis.core.mixins import ExtensibleForm
from aleksis.core.models import Group, Person
......@@ -38,6 +39,19 @@ LICENCE_CHOICES = [
]
class ArrayFieldCheckboxSelectMultiple(widgets.CheckboxSelectMultiple):
"""Widget splitting the data coming from ArrayField."""
def format_value(self, value):
"""Return selected values as a list."""
if value is None and self.allow_multiple_selected:
return []
if not isinstance(value, (tuple, list)):
value = value.split()
return [str(v) if v is not None else "" for v in value]
class EditEventForm(ExtensibleForm):
"""Form to create or edit an event."""
......@@ -48,7 +62,13 @@ class EditEventForm(ExtensibleForm):
Row("display_name", "slug", "description"),
Row("place", "published"),
Fieldset(_("Date data"), Row("date_event", "date_registration", "date_retraction")),
Fieldset(_("Event details"), Row("cost", "max_participants"), "information"),
Fieldset(
_("Event details"),
Row("cost", "min_cost", "max_cost", "max_participants"),
"information",
"additional_fields",
"contact_information_visible_fields",
),
Fieldset(_("Terms"), "terms"),
Fieldset(_("Info mailings"), "info_mailings"),
),
......@@ -67,10 +87,14 @@ class EditEventForm(ExtensibleForm):
"date_registration",
"date_retraction",
"cost",
"min_cost",
"max_cost",
"max_participants",
"terms",
"information",
"info_mailings",
"additional_fields",
"contact_information_visible_fields",
]
widgets = {
"linked_group": ModelSelect2Widget(
......@@ -85,6 +109,22 @@ class EditEventForm(ExtensibleForm):
search_fields=["subject__icontains"],
attrs={"data-minimum-input-length": 0, "class": "browser-default"},
),
"additional_fields": ModelSelect2MultipleWidget(
search_fields=["title__icontains"],
attrs={"data-minimum-input-length": 0, "class": "browser-default"},
),
"contact_information_visible_fields": ArrayFieldCheckboxSelectMultiple(
choices=[
("date_of_birth", _("Date of birth")),
("sex", _("Sex")),
("street", _("Street")),
("housenumber", _("House number")),
("postal_code", _("Postal code")),
("place", _("Place")),
("mobile_number", _("Mobile number")),
("school_details", _("School details")),
]
),
}
......@@ -93,7 +133,7 @@ class EditVoucherForm(forms.ModelForm):
class Meta:
model = Voucher
exclude = ["code", "used_person_uid", "used", "deleted"]
exclude = ["code", "used_person_uid", "used", "deleted"] # noqa
widgets = {
"event": ModelSelect2Widget(
search_fields=["display_name__icontains"],
......@@ -183,104 +223,128 @@ class RegisterEventContactDetails(ExtensibleForm):
model = Group
fields = []
layout = Layout(
Fieldset(
_("Personal data"),
Row("first_name", "last_name"),
Row("date_of_birth", "sex"),
),
Fieldset(
_("Address data"),
Row("street", "housenumber"),
Row("postal_code", "place"),
),
Fieldset(
_("Contact details"),
Row("mobile_number", "email"),
),
Fieldset(
_("School details"),
Row("school", "school_place", "school_class"),
),
)
first_name = forms.CharField(
label=_("First name"),
disabled=True,
)
last_name = forms.CharField(
label=_("Last name"),
disabled=True,
)
street = forms.CharField(
label=_("Street"),
)
housenumber = forms.CharField(
label=_("Housenumber"),
)
postal_code = forms.CharField(
label=_("Postal code"),
)
@classmethod
def clear_layout(cls):
cls.base_layout = [
Fieldset(
_("Name"),
Row("first_name", "last_name"),
)
]
cls.layout = Layout(*cls.base_layout)
place = forms.CharField(
label=_("Place"),
)
def __init__(self, event, *args, **kwargs):
super().__init__(*args, **kwargs)
mobile_number = PhoneNumberField(
label=_("Mobile number"),
required=False,
help_text=_(
"Your mobile number helps us to reach you in an emergency during the event, e.g. "
"if you are alone with your group at a conference or similar. If you don't have a "
"cell phone, you can leave the field blank."
),
)
self.clear_layout()
date_of_birth = forms.DateField(
label=_("Date of birth"),
)
self.fields["first_name"] = forms.CharField(
label=_("First name"),
disabled=True,
)
sex = forms.ChoiceField(
label=_("Sex"),
help_text=_(
"For various reasons, e.g. because we have to keep gender segregation during the night "
"for legal reasons, we need to know if you are a boy or a girl."
),
choices=Person.SEX_CHOICES,
initial=None,
)
self.fields["last_name"] = forms.CharField(
label=_("Last name"),
disabled=True,
)
email = forms.EmailField(
label=_("Email address"),
help_text=_(
"Please use your personal e-mail address here, which you will check "
"personally. Important information will always be sent to your parents "
"as well. Do not use an e-mail address owned by your parents here."
),
)
if (
"date_of_birth" in event.contact_information_visible_fields
or "sex" in event.contact_information_visible_fields
):
active_fields = []
if "date_of_birth" in event.contact_information_visible_fields:
active_fields.append("date_of_birth")
self.fields["date_of_birth"] = forms.DateField(
label=_("Date of birth"),
)
if "sex" in event.contact_information_visible_fields:
active_fields.append("sex")
self.fields["sex"] = forms.ChoiceField(
label=_("Sex"),
help_text=_(
"For various reasons, e.g. because we have to keep gender segregation during the night "
"for legal reasons, we need to know if you are a boy or a girl."
),
choices=Person.SEX_CHOICES,
initial=None,
)
node = Fieldset(_("Personal information"), *active_fields)
self.add_node_to_layout(node, add_fields=False)
if (
"street" in event.contact_information_visible_fields
or "housenumber" in event.contact_information_visible_fields
or "postal_code" in event.contact_information_visible_fields
or "place" in event.contact_information_visible_fields
):
active_fields = []
if "street" in event.contact_information_visible_fields:
active_fields.append("street")
self.fields["street"] = forms.CharField(
label=_("Street"),
)
if "housenumber" in event.contact_information_visible_fields:
active_fields.append("housenumber")
self.fields["housenumber"] = forms.CharField(
label=_("Housenumber"),
)
if "postal_code" in event.contact_information_visible_fields:
active_fields.append("postal_code")
self.fields["postal_code"] = forms.CharField(
label=_("Postal code"),
)
if "place" in event.contact_information_visible_fields:
active_fields.append("place")
self.fields["place"] = forms.CharField(
label=_("Place"),
)
self.add_node_to_layout(Fieldset(_("Address data"), *active_fields), add_fields=False)
self.fields["email"] = forms.EmailField(
label=_("Email address"),
help_text=_(
"Please use your personal e-mail address here, which you will check "
"personally. Important information will always be sent to your parents "
"as well. Do not use an e-mail address owned by your parents here."
),
)
if "mobile_number" in event.contact_information_visible_fields:
self.fields["mobile_number"] = PhoneNumberField(
label=_("Mobile number"),
required=False,
help_text=_(
"Your mobile number helps us to reach you in an emergency during the event, e.g. "
"if you are alone with your group at a conference or similar. If you don't have a "
"cell phone, you can leave the field blank."
),
)
contact_details_fields = ["mobile_number", "email"]
else:
contact_details_fields = ["email"]
school = forms.CharField(
label=_("School"),
help_text=_("Please enter the name of your school."),
)
node = Fieldset(_("Contact details"), *contact_details_fields)
self.add_node_to_layout(node, add_fields=False)
school_place = forms.CharField(
label=_("School place"),
help_text=_("Enter the place (city) where your school is located."),
)
if "school_details" in event.contact_information_visible_fields:
self.fields["school"] = forms.CharField(
label=_("School"),
help_text=_("Please enter the name of your school."),
)
self.fields["school_place"] = forms.CharField(
label=_("School place"),
help_text=_("Enter the place (city) where your school is located."),
)
self.fields["school_class"] = forms.CharField(
label=_("School class"),
help_text=_("Please enter the class you are in (e.g. 8a)."),
)
school_class = forms.CharField(
label=_("School class"),
help_text=_("Please enter the class you are in (e.g. 8a)."),
)
node = Fieldset(_("School details"), "school", "school_place", "school_class")
self.add_node_to_layout(node, add_fields=False)
class RegisterEventAdditional(ExtensibleForm):
layout = Layout(
Fieldset(
_("Medical information / intolerances"),
......@@ -309,7 +373,7 @@ class RegisterEventAdditional(ExtensibleForm):
self.__class__.layout_filled = getattr(self.__class__, "layout_filled", False)
for field in event.linked_group.additional_fields.all():
for field in event.additional_fields.all():
field_instance = getattr(fields, field.field_type)(
required=field.required,
help_text=field.help_text,
......@@ -317,7 +381,7 @@ class RegisterEventAdditional(ExtensibleForm):
self.fields[field.title] = field_instance
if not self.layout_filled:
node = Fieldset(f"{field.title}", f"{field.title}")
self.add_node_to_layout(node)
self.add_node_to_layout(node, add_fields=False)
self.__class__.layout_filled = True
......@@ -349,9 +413,17 @@ class RegisterEventFinancial(ExtensibleForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["payment_method"].choices = InvoiceGroup.objects.get(
name="Hack'n'Fun-Veranstaltungen"
).get_variant_choices()
# FIXME Maybe do not hard-code this
client, __ = Client.objects.get_or_create(name="Teckids e.V.")
group, __ = InvoiceGroup.objects.get_or_create(
name="Hack'n'Fun-Veranstaltungen",
client=client,
defaults={
"template_name": "paweljong/invoice_pdf.html",
},
)
self.fields["payment_method"].choices = group.get_variant_choices()
class Meta:
model = EventRegistration
......@@ -383,8 +455,8 @@ class RegisterEventConsent(ExtensibleForm):
label=field.confirmation_text,
)
self.fields[f"consent_{field.pk}"] = field_instance
node = Row(f"consent_{field.pk}")
self.add_node_to_layout(node)
node = f"consent_{field.pk}"
self.add_node_to_layout(node, add_fields=False)
if event.date_retraction:
field_instance = forms.BooleanField(
......@@ -397,12 +469,11 @@ class RegisterEventConsent(ExtensibleForm):
),
)
self.fields["retraction_deadline"] = field_instance
node = Row("retraction_deadline")
self.add_node_to_layout(node)
node = "retraction_deadline"
self.add_node_to_layout(node, add_fields=False)
class EditEventRegistrationForm(forms.ModelForm):
layout = Layout(
Row("event", "person"),
Row("comment", "medical_information"),
......@@ -415,13 +486,13 @@ class EditEventRegistrationForm(forms.ModelForm):
class Meta:
model = EventRegistration
exclude = []
exclude = [] # noqa
class EditTermForm(forms.ModelForm):
class Meta:
model = Terms
exclude = []
exclude = [] # noqa
class RegisterEventAccount(SignupForm, ExtensibleForm):
......@@ -434,7 +505,7 @@ class RegisterEventAccount(SignupForm, ExtensibleForm):
layout = Layout(
Fieldset(
_("Base data"),
Row("first_name", "last_name", "date_of_birth"),
Row("first_name", "last_name"),
),
Fieldset(
_("Account data"),
......@@ -446,7 +517,6 @@ class RegisterEventAccount(SignupForm, ExtensibleForm):
first_name = forms.CharField(label=_("First name"))
last_name = forms.CharField(label=_("Last name"))
date_of_birth = forms.DateField(label=_("Date of birth"))
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
......@@ -458,7 +528,6 @@ class RegisterEventAccount(SignupForm, ExtensibleForm):
class EditInfoMailingForm(forms.ModelForm):
layout = Layout(
Row("sender", "reply_to", "active"),
Row("send_to_person", "send_to_guardians", "send_to_retracted", "send_to_not_checked_in"),
......@@ -468,11 +537,10 @@ class EditInfoMailingForm(forms.ModelForm):
class Meta:
model = InfoMailing
exclude = ["sent_to"]
exclude = ["sent_to"] # noqa
class RegistrationNotificationForm(forms.ModelForm):
layout = Layout(
Row("sender", "reply_to"),
Row("send_to_person", "send_to_guardians"),
......@@ -482,13 +550,13 @@ class RegistrationNotificationForm(forms.ModelForm):
class Meta:
model = InfoMailing
exclude = ["sent_to", "active"]
exclude = ["sent_to", "active"] # noqa
class RegistrationStatesForm(forms.ModelForm):
class Meta:
model = RegistrationState
exclude = []
exclude = [] # noqa
class PersonGroupFormPerson(forms.Form):
......@@ -550,3 +618,36 @@ class EventCheckpointForm(forms.Form):
decimal_places=8,
widget=forms.HiddenInput(),
)
class RegisterAccountForm(SignupForm, ExtensibleForm):
"""Form to register new user accounts."""
class Meta:
model = EventRegistration
fields = []
layout = Layout(
Fieldset(
_("Base data"),
Row("first_name", "last_name", "date_of_birth"),
),
Fieldset(
_("Account data"),
"username",
Row("email", "email2"),
Row("password1", "password2"),
),
)
first_name = forms.CharField(label=_("First name"))
last_name = forms.CharField(label=_("Last name"))
date_of_birth = forms.DateField(label=_("Date of birth"))
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["username"].help_text = _(
"The username must only contain lower case letters and numbers, "
"and must begin with a letter."
)
<template>
<div>
<v-form ref="form">
<v-text-field v-model="comment" label="Comment" required></v-text-field>
<v-btn color="success" class="mr-4" @click="startScan"> Check in </v-btn>
</v-form>
<v-card class="mx-auto">
<v-alert :color="status.color">
{{ status.message }}
</v-alert>
</v-card>
<v-card class="mx-auto">
<v-alert v-for="(checkIn, i) in checkIns" :key="i" :color="checkIn.color">
{{ checkIn.message }}
</v-alert>
</v-card>
</div>
</template>
<script>
import gql from "graphql-tag";
export default {
data() {
return {
comment: "",
status: {
color: "blue-grey",
message: "Scan not started",
},
checkIns: new Array(),
};
},
methods: {
checkIn(data, statusObject) {
this.$apollo
.mutate({
mutation: gql`
mutation (
$eventSlug: String!
$personId: Int!
$comment: String!
$lat: Int
$lon: Int
) {
checkpointCheckIn(
eventSlug: $eventSlug
personId: $personId
comment: $comment
lat: $lat
lon: $lon
) {
checkpoint {
id
}
}
}
`,
variables: {
eventSlug: this.$route.params.slug,
personId: data.id,
comment: this.comment,
},
})
.then((data) => {
statusObject.message = `Checked in ${data.user.username}`;
statusObject.color = "green";
})
.catch((error) => {
statusObject.message = `Error checking in ${data.user.username}`;
statusObject.color = "red";
});
},
startScan() {
try {
const ndef = new NDEFReader();
ndef.scan().then(() => {
this.status.color = "blue-grey";
this.status.message = "Scanning...";
ndef.addEventListener("readingerror", (err) => {
// FIXME use semantic colors/types
this.status.color = "red";
this.status.message = err;
});
ndef.addEventListener("reading", (e) => {
const message = e.message;
const checkInStatus = {
color: "blue-grey",
message: "Decoding...",
};
this.checkIns.unshift(checkInStatus);
for (const record of message.records) {
if (record.recordType !== "url") {
checkInStatus.message = "Found non-URL";
continue;
}
const decoder = new TextDecoder();
const url = decoder.decode(record.data);
// FIXME use configured base URL here
if (!url.startsWith("https://ticdesk.teckids.org/o/")) {
checkInStatus.message = "Found invalid URL";
checkInStatus.color = "red";
break;
}
fetch(url)
.then((res) => res.json())
.then((data) => {
checkInStatus.message = `Checking in ${data.user.username}...`;
checkInStatus.color = "orange";
this.checkIn(data, checkInStatus);
})
.catch((error) => {
checkInStatus.message = "Error retrieving or decoding data";
checkInStatus.color = "red";
});
}
});
});
} catch {
console.log("Error");
}
},
},
};
</script>
query eventById($id: ID!) {
eventById(id: $id) {
id
displayName
description
cost
minCost
maxCost
terms {
id
}
additionalFields {
id
}
}
}
query eventBySlug($slug: String!) {
event: eventBySlug(slug: $slug) {
id
displayName
description
cost
minCost
maxCost
dateRetraction
terms {
id
title
term
confirmationText
}
additionalFields {
id
title
fieldType
required
helpText
}
contactInformationVisibleFields
}
}
<script setup>
import InlineCRUDList from "aleksis.core/components/generic/InlineCRUDList.vue";
</script>
<template>
<inline-c-r-u-d-list
:headers="headers"
:i18n-key="i18nKey"
create-item-i18n-key="paweljong.event_additional_field.create"
:gql-query="gqlQuery"
:gql-create-mutation="gqlCreateMutation"
:gql-patch-mutation="gqlPatchMutation"
:gql-delete-mutation="gqlDeleteMutation"
:default-item="defaultItem"
:get-create-data="getCreateData"
:get-patch-data="getPatchData"
>
<!-- eslint-disable-next-line vue/valid-v-slot -->
<template #fieldTitle.field="{ attrs, on, isCreate }">
<div aria-required="true">
<v-text-field v-bind="attrs" v-on="on" required :rules="required" />
</div>
</template>
<template #required="{ item }">
<v-chip v-if="item.required" color="error" outlined>
{{ $t("paweljong.event_additional_field.required.required") }}
</v-chip>
<v-chip v-else color="success" outlined>
{{ $t("paweljong.event_additional_field.required.optional") }}
</v-chip>
</template>
<!-- eslint-disable-next-line vue/valid-v-slot -->
<template #required.field="{ attrs, on, isCreate }">
<v-checkbox v-bind="attrs" v-on="on" />
</template>
<template #fieldType="{ item }">
{{ $t(`paweljong.event_additional_field.field_type.${item.fieldType}`) }}
</template>
<!-- eslint-disable-next-line vue/valid-v-slot -->
<template #fieldType.field="{ attrs, on, isCreate }">
<div aria-required="true">
<v-autocomplete
v-bind="attrs"
v-on="on"
item-text="text"
item-value="value"
:items="fieldTypeItems"
:rules="required"
/>
</div>
</template>
</inline-c-r-u-d-list>
</template>
<script>
import {
eventAdditionalFields,
createEventAdditionalFields,
deleteEventAdditionalFields,
updateEventAdditionalFields,
} from "./eventAdditionalField.graphql";
export default {
name: "EventAdditionalFieldsInlineList",
data() {
return {
headers: [
{
text: this.$t("paweljong.event_additional_field.field_title"),
value: "fieldTitle",
},
{
text: this.$t(
"paweljong.event_additional_field.field_type.form_field_name",
),
value: "fieldType",
},
{
text: this.$t(
"paweljong.event_additional_field.required.form_field_name",
),
value: "required",
},
{
text: this.$t("paweljong.event_additional_field.help_text"),
value: "helpText",
},
],
i18nKey: "paweljong.event_additional_field",
gqlQuery: eventAdditionalFields,
gqlCreateMutation: createEventAdditionalFields,
gqlPatchMutation: updateEventAdditionalFields,
gqlDeleteMutation: deleteEventAdditionalFields,
defaultItem: {
title: "",
fieldType: "",
required: false,
helpText: "",
},
required: [(value) => !!value || this.$t("forms.errors.required")],
};
},
methods: {
getCreateData(item) {
let { fieldTitle: _, ...filteredObj } = item;
return {
...filteredObj,
required: !!item.required,
title: item.fieldTitle,
};
},
getPatchData(item) {
if ("required" in item) {
let { fieldTitle: _, ...filteredObj } = item;
return {
...filteredObj,
required: !!item.required,
title: item.fieldTitle,
};
}
return item;
},
},
computed: {
fieldTypeItems() {
return [
"BOOLEANFIELD",
"CHARFIELD",
"DATEFIELD",
"DATETIMEFIELD",
"DECIMALFIELD",
"EMAILFIELD",
"INTEGERFIELD",
"GENERICIPADDRESSFIELD",
"NULLBOOLEANFIELD",
"TEXTFIELD",
"TIMEFIELD",
"URLFIELD",
].map((item) => ({
value: item,
text: this.$t(`paweljong.event_additional_field.field_type.${item}`),
}));
},
},
};
</script>
<style scoped></style>
query eventAdditionalFields($orderBy: [String], $filters: JSONString) {
items: eventAdditionalFields(orderBy: $orderBy, filters: $filters) {
id
fieldTitle: title
fieldType
required
helpText
canEdit
canDelete
}
}
mutation createEventAdditionalFields(
$input: [BatchCreateEventAdditionalFieldInput]!
) {
createEventAdditionalFields(input: $input) {
items: eventAdditionalFields {
id
fieldTitle: title
fieldType
required
helpText
canEdit
canDelete
}
}
}
mutation deleteEventAdditionalFields($ids: [ID]!) {
deleteEventAdditionalFields(ids: $ids) {
deletionCount
}
}
mutation updateEventAdditionalFields(
$input: [BatchPatchEventAdditionalFieldInput]!
) {
updateEventAdditionalFields(input: $input) {
items: eventAdditionalFields {
id
fieldTitle: title
fieldType
required
helpText
canEdit
canDelete
}
}
}
/**
* Vue mixin containing code getting the respective vue component for event additional fields.
*
* Only used by event registration form, but factored out for readability.
*/
// TODO: add some more rule checking (e.g. for emails)
import DateField from "aleksis.core/components/generic/forms/DateField.vue";
import DateTimeField from "aleksis.core/components/generic/forms/DateTimeField.vue";
import TimeField from "aleksis.core/components/generic/forms/TimeField.vue";
import PositiveSmallIntegerField from "aleksis.core/components/generic/forms/PositiveSmallIntegerField.vue";
const eventAdditionalFieldMixin = {
methods: {
fieldComponentForAdditionalField(additionalField) {
if (
additionalField.fieldType == "CHARFIELD" ||
additionalField.fieldType == "EMAILFIELD" ||
additionalField.fieldType == "URLFIELD" ||
additionalField.fieldType == "GENERICIPADDRESSFIELD"
) {
return "v-text-field";
} else if (
additionalField.fieldType == "BOOLEANFIELD" ||
additionalField.fieldType == "NULLBOOLEANFIELD"
) {
// TODO: implement proper null boolean input
return "v-checkbox";
} else if (additionalField.fieldType == "DATEFIELD") {
return DateField;
} else if (additionalField.fieldType == "DATETIMEFIELD") {
return DateTimeField;
} else if (additionalField.fieldType == "TIMEFIELD") {
return TimeField;
} else if (
additionalField.fieldType == "INTEGERFIELD" ||
additionalField.fieldType == "DECIMALFIELD"
) {
// TODO: implement proper decimal input
return PositiveSmallIntegerField;
}
return "";
},
},
};
export default eventAdditionalFieldMixin;
<template>
<v-row v-if="participantHelpText || guardianHelpText" class="mb-2">
<v-col
v-if="participantHelpText"
cols="12"
:md="guardianHelpText ? '6' : '12'"
>
<v-card>
<v-card-title>
{{ $t("paweljong.event_registration.form.help_text.participant") }}
</v-card-title>
<v-card-text>{{ participantHelpText }}</v-card-text>
</v-card>
</v-col>
<v-col
v-if="guardianHelpText"
cols="12"
:md="participantHelpText ? '6' : '12'"
>
<v-card>
<v-card-title>
{{ $t("paweljong.event_registration.form.help_text.guardian") }}
</v-card-title>
<v-card-text>{{ guardianHelpText }}</v-card-text>
</v-card>
</v-col>
</v-row>
</template>
<script>
export default {
name: "EventRegistrationHelpTextCards",
props: {
participantHelpText: {
type: String,
required: false,
default: "",
},
guardianHelpText: {
type: String,
required: false,
default: "",
},
},
};
</script>
mutation sendEventRegistration(
$event: ID!
$eventRegistration: EventRegistrationInputType!
) {
sendEventRegistration(event: $event, eventRegistration: $eventRegistration) {
ok
doPaymentToken
}
}
query whoAmI {
whoAmI {
id
person {
id
firstName
lastName
guardians {
id
firstName
lastName
mobileNumber
email
}
mobileNumber
sex
street
housenumber
postalCode
place
dateOfBirth
}
}
}
query gqlPaweljongPaymentChoices {
paweljongPaymentChoices {
variant
text
}
}
query gqlPaweljongSitePreferences {
paweljongSitePreferences {
eventRegistrationEmailParticipantHelpText
eventRegistrationRegisterParticipantHelpText
eventRegistrationContactDetailsParticipantHelpText
eventRegistrationGuardiansParticipantHelpText
eventRegistrationAdditionalParticipantHelpText
eventRegistrationFinancialParticipantHelpText
eventRegistrationConsentParticipantHelpText
eventRegistrationConfirmParticipantHelpText
eventRegistrationEmailGuardianHelpText
eventRegistrationRegisterGuardianHelpText
eventRegistrationContactDetailsGuardianHelpText
eventRegistrationGuardiansGuardianHelpText
eventRegistrationAdditionalGuardianHelpText
eventRegistrationFinancialGuardianHelpText
eventRegistrationConsentGuardianHelpText
eventRegistrationConfirmGuardianHelpText
}
}
import {
notLoggedInValidator,
hasPersonValidator,
} from "aleksis.core/routeValidators";
export default {
meta: {
inMenu: true,
titleKey: "paweljong.events.menu_title",
icon: "mdi-calendar-text",
validators: [hasPersonValidator],
permission: "paweljong.view_menu",
},
children: [
{
path: "event/:slug/edit/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.editEventBySlug",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/:slug/terms/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.viewEventTermsBySlug",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/:slug/register/",
component: () =>
import("./components/event_registration/EventRegistrationForm.vue"),
name: "paweljong.registerEventBySlug",
props: true,
},
{
path: "group_persons/:pk/add/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.addPersonsToGroup",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/:slug/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.eventByName",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/:slug/detail/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.eventDetailByName",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/:slug/checkpoint/",
component: () => import("./components/event/Checkpoint.vue"),
name: "paweljong.eventByNameCheckpoint",
},
{
path: "event/:slug/start/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.registerEventBySlugStart",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "misc/set_email_needed/:slug/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.setEmailNeeded",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "misc/set_email_needed/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.setEmailNeededNoSlug",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "account/register/start/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.registerAccountStart",
meta: {
inMenu: true,
titleKey: "paweljong.register.menu_title",
icon: "mdi-account-check-outline",
validators: [notLoggedInValidator],
},
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "account/register/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.registerAccount",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "events/feed/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.upcomingEventsRssFeed",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "events/create/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.createEvent",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "events/manage/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.manageEvents",
meta: {
inMenu: true,
titleKey: "paweljong.events.manage_events.menu_title",
icon: "mdi-calendar-edit",
permission: "paweljong.change_events_rule",
},
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "vouchers/create/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.createVouchers",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "vouchers/:pk/delete/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.deleteVoucherByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "vouchers/:pk/edit/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.editVoucherByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "vouchers/:pk/print/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.printVoucherByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "vouchers/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.vouchers",
meta: {
inMenu: true,
titleKey: "paweljong.events.vouchers.menu_title",
icon: "mdi-ticket-confirmation-outline",
permission: "paweljong.view_vouchers_rule",
},
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/lists/generate/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.generateLists",
meta: {
inMenu: true,
titleKey: "paweljong.events.generate_lists.menu_title",
icon: "mdi-format-list-numbered",
permission: "paweljong.generate_lists_rule",
},
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/registrations/:pk/check_in/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.checkInRegistrationByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/registrations/:pk/pay/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.payRegistrationByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/registrations/:pk/retract/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.retractRegistrationByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/registrations/:pk/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.registrationByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/registrations/:pk/edit/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.editRegistrationByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/registrations/:pk/delete/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.deleteRegistrationByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/registrations/:pk/notification/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.registrationNotificationByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/terms/list/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.terms",
meta: {
inMenu: true,
titleKey: "paweljong.events.terms.menu_title",
icon: "mdi-gavel",
permission: "paweljong.view_terms_rule",
},
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/terms/create/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.createTerm",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/terms/:pk/edit/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.editTermByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/registrations/states/list/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.registrationStates",
meta: {
inMenu: true,
titleKey: "paweljong.events.registration_states.menu_title",
icon: "mdi-list-status",
permission: "paweljong.view_registration_states_rule",
},
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/registrations/states/create/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.createRegistrationState",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event/registrations/states/:pk/edit/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.editRegistrationStateByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "info_mailings/list/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.infoMailings",
meta: {
inMenu: true,
titleKey: "paweljong.events.info_mailings.menu_title",
icon: "mdi-email-alert-outline",
permission: "paweljong.view_info_mailings_rule",
},
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "info_mailings/create/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.createInfoMailing",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "info_mailings/:pk/edit/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.editInfoMailingByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "info_mailings/:pk/delete/",
component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
name: "paweljong.deleteInfoMailingByPk",
props: {
byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
},
},
{
path: "event_additional_fields/",
component: () =>
import(
"./components/event_additional_field/EventAdditionalFieldList.vue"
),
name: "paweljong.eventAdditionalFieldList",
meta: {
inMenu: true,
titleKey: "paweljong.event_additional_field.menu_title",
icon: "mdi-list-status",
permission: "paweljong.view_event_additional_fields_rule",
},
},
],
};
{
"paweljong": {
"events": {
"menu_title": "Veranstaltungen",
"vouchers": {
"menu_title": "Gutscheine"
},
"terms": {
"menu_title": "Bedingungen"
},
"registration_states": {
"menu_title": "Registrierungsstatus"
},
"info_mailings": {
"menu_title": "Info-Mailings"
},
"generate_lists": {
"menu_title": "Teilnehmendenliste generieren"
},
"manage_events": {
"menu_title": "Veranstaltungen verwalten"
}
},
"register": {
"menu_title": "Registrieren"
},
"event_additional_field": {
"create": "Zusätzliche Felder für Veranstaltungen erstellen",
"title": "Zusätzliches Feld für Veranstaltung",
"field_title": "Titel",
"title_plural": "Zusätzliche Felder für Veranstaltungen",
"menu_title": "Zusätzliche Felder für Veranstaltungen",
"field_type": {
"form_field_name": "Feld-Typ",
"BOOLEANFIELD": "Boolescher Wert (Ja/Nein)",
"CHARFIELD": "Text (einzeilig)",
"DATEFIELD": "Datum",
"DATETIMEFIELD": "Datum und Uhrzeit",
"DECIMALFIELD": "Dezimalzahl",
"EMAILFIELD": "E-Mail-Adresse",
"INTEGERFIELD": "Zahl",
"GENERICIPADDRESSFIELD": "IP-Adresse",
"NULLBOOLEANFIELD": "Boolescher Wert oder leer (Ja/Nein/Leer)",
"TEXTFIELD": "Text (mehrzeilig)",
"TIMEFIELD": "Uhrzeit",
"URLFIELD": "URL / Link"
},
"required": {
"form_field_name": "Verpflichtend",
"required": "Verpflichtend",
"optional": "Optional"
},
"help_text": "Hilfe-Text"
},
"event_registration": {
"form": {
"submitted": {
"thank_you": "Danke!",
"submitted_successfully": "Deine Anmeldung wurde erfolgreich abgeschickt.",
"payment_text": "Du musst noch den Zahlungsvorgang für deine Anmeldung abschließen.",
"payment_button": "Zahlung abschließen"
},
"steps": {
"email": {
"title": "E-Mail-Adresse",
"choose_mode": {
"continue_aleksis": "Neue E-Mail-Adresse",
"continue_own": "Bestehende E-Mail-Adresse",
"continue_existing_account": "Ich habe bereits ein Konto",
"back": "Zurück"
},
"fields": {
"email": {
"label": "E-Mail-Adresse"
},
"confirm_email": {
"label": "E-Mail-Adresse bestätigen"
}
}
},
"register": {
"title": "Konto",
"fields": {
"first_name": {
"label": "Vorname"
},
"last_name": {
"label": "Nachname"
},
"username": {
"label": "Benutzername"
},
"password": {
"label": "Passwort"
},
"confirm_password": {
"label": "Passwort bestätigen"
}
}
},
"contact_details": {
"title": "Kontaktinformationen",
"fields": {
"first_name": {
"label": "Vorname"
},
"last_name": {
"label": "Nachname"
},
"date_of_birth": {
"label": "Geburtsdatum"
},
"sex": {
"label": "Geschlecht",
"help_text": "Aus verschiedenen Gründen, z. B. weil wir aus rechtlichen Gründen nachts eine geschlechtergetrennte Unterbringung einhalten müssen, müssen wir wissen, ob du ein Junge oder ein Mädchen bist."
},
"street": {
"label": "Straße"
},
"housenumber": {
"label": "Hausnummer"
},
"postal_code": {
"label": "Postleitzahl"
},
"place": {
"label": "Ort"
},
"email": {
"label": "E-Mail-Adresse",
"help_text": "Bitte gib hier deine persönliche E-Mail-Adresse an, die du regelmäßig abrufst. Wichtige Informationen werden immer auch an deine Eltern gesendet. Verwende hier keine E-Mail-Adresse deiner Eltern."
},
"mobile_number": {
"label": "Handynummer",
"help_text": "Deine Handynummer hilft uns, dich im Notfall während der Veranstaltung zu erreichen, z. B. wenn du mit deiner Gruppe auf einer Konferenz unterwegs bist. Falls du kein Handy hast, kannst du das Feld leer lassen."
},
"school": {
"label": "Schule",
"help_text": "Bitte gib den Namen deiner Schule ein."
},
"school_place": {
"label": "Schulort",
"help_text": "Gib den Ort (Stadt) an, in dem sich deine Schule befindet."
},
"school_class": {
"label": "Klasse",
"help_text": "Bitte gib deine aktuelle Klasse an (z. B. 8a)."
}
}
},
"guardians": {
"title": "Erziehungsberechtigte",
"counter": "Erziehungsberechtigter {i}",
"add": "Erziehungsberechtigten hinzufügen",
"fields": {
"first_name": {
"label": "Vorname des Erziehungsberechtigten",
"help_text": "Bitte gib den Vornamen des Erziehungsberechtigten an, der das Anmeldeformular mit dir ausfüllt und während der Veranstaltung in Notfällen erreichbar ist."
},
"last_name": {
"label": "Nachname des Erziehungsberechtigten",
"help_text": "Bitte gib den Nachnamen des Erziehungsberechtigten an, der das Anmeldeformular mit dir ausfüllt und während der Veranstaltung in Notfällen erreichbar ist."
},
"email": {
"label": "E-Mail-Adresse des Erziehungsberechtigten"
},
"mobile_number": {
"label": "Handynummer des Erziehungsberechtigten",
"help_text": "Wir benötigen die Handynummer für Notfälle, falls wir deine Eltern während der Veranstaltung dringend erreichen müssen."
}
}
},
"additional": {
"title": "Zusätzliche Informationen",
"fields": {
"medical_information": {
"label": "Medizinische Informationen / Unverträglichkeiten",
"help_text": "Falls es medizinisch wichtige Dinge gibt, die wir beachten müssen, z. B. bei der Essenszubereitung oder zur Einnahme verschriebener Medikamente, gib diese bitte hier an."
}
}
},
"financial": {
"title": "Bezahlung",
"help_text": {
"cost": "Tatsächliche Kosten",
"max_cost": "Maximal zu zahlender Betrag",
"min_cost": "Minimal zu zahlender Betrag"
},
"fields": {
"payment_method": {
"label": "Zahlungsmethode",
"help_text": "Bitte wähle eine Zahlungsmethode. Die tatsächliche Zahlung erfolgt nach der Anmeldung."
},
"voucher_code": {
"label": "Gutscheincode",
"help_text": "Falls du einen Gutscheincode hast, gib ihn hier ein."
},
"amount": {
"label": "Von dir gezahlter Betrag (in €)"
}
}
},
"consent": {
"title": "Einverständniserklärung",
"fields": {
"retraction_consent": {
"label": "Ich bestätige, dass die Rücknahme der Anmeldung nach dem {date} nicht mehr möglich ist."
}
}
},
"confirm": {
"title": "Bestätigen",
"hint": "Nach diesem Schritt kannst du deine Anmeldung nicht mehr bearbeiten.",
"fields": {
"comment": {
"label": "Weitere Anmerkungen",
"help_text": "Hier kannst du uns zusätzliche Anmerkungen mitteilen."
}
}
}
},
"rules": {
"email": {
"valid": "Dies ist keine gültige E-Mail-Adresse"
},
"confirm_email": {
"no_match": "Die E-Mail-Adressen stimmen nicht überein"
},
"confirm_password": {
"no_match": "Die Passwörter stimmen nicht überein"
},
"amount": {
"too_high": "Der Betrag ist höher als der maximal zu zahlende Betrag.",
"too_low": "Der Betrag ist niedriger als der minimal zu zahlende Betrag."
}
},
"help_text": {
"guardian": "Für Erziehungsberechtigte",
"participant": "Für Teilnehmende"
}
}
}
}
}
{
"paweljong": {
"register": {
"menu_title": "Register"
},
"events": {
"menu_title": "Events",
"vouchers": {
"menu_title": "Vouchers"
},
"terms": {
"menu_title": "Terms"
},
"registration_states": {
"menu_title": "Registration states"
},
"info_mailings": {
"menu_title": "Info mailings"
},
"generate_lists": {
"menu_title": "Generate participant list"
},
"manage_events": {
"menu_title": "Manage events"
}
},
"event_additional_field": {
"create": "Create additional field for events",
"title": "Additional Field for Event",
"field_title": "Title",
"title_plural": "Additional Fields For Events",
"menu_title": "Additional Event Fields",
"field_type": {
"form_field_name": "Field Type",
"BOOLEANFIELD": "Boolean (Yes/No)",
"CHARFIELD": "Text (one line)",
"DATEFIELD": "Date",
"DATETIMEFIELD": "Date and time",
"DECIMALFIELD": "Decimal number",
"EMAILFIELD": "E-mail address",
"INTEGERFIELD": "Integer",
"GENERICIPADDRESSFIELD": "IP address",
"NULLBOOLEANFIELD": "Boolean or empty (Yes/No/Neither)",
"TEXTFIELD": "Text (multi-line)",
"TIMEFIELD": "Time",
"URLFIELD": "URL / Link"
},
"required": {
"form_field_name": "Required",
"required": "Required",
"optional": "Optional"
},
"help_text": "Helptext"
},
"event_registration": {
"form": {
"submitted": {
"thank_you": "Thanks!",
"submitted_successfully": "Your registration was submitted successfully.",
"payment_text": "You need to finish the payment process for your registration.",
"payment_button": "Finish payment"
},
"steps": {
"email": {
"title": "E-Mail address",
"choose_mode": {
"continue_aleksis": "New email address",
"continue_own": "Existing email address",
"continue_existing_account": "I already have an account",
"back": "Go back"
},
"fields": {
"email": {
"label": "E-Mail address"
},
"confirm_email": {
"label": "Confirm e-mail address"
}
}
},
"register": {
"title": "Account",
"fields": {
"first_name": {
"label": "First name"
},
"last_name": {
"label": "Last name"
},
"username": {
"label": "Username"
},
"password": {
"label": "Password"
},
"confirm_password": {
"label": "Confirm password"
}
}
},
"contact_details": {
"title": "Contact information",
"fields": {
"first_name": {
"label": "First name"
},
"last_name": {
"label": "Last name"
},
"date_of_birth": {
"label": "Date of birth"
},
"sex": {
"label": "Sex",
"help_text": "For various reasons, e.g. because we have to keep gender segregation during the night for legal reasons, we need to know if you are a boy or a girl."
},
"street": {
"label": "Street"
},
"housenumber": {
"label": "Housenumber"
},
"postal_code": {
"label": "Postal code"
},
"place": {
"label": "Place"
},
"email": {
"label": "E-Mail address",
"help_text": "Please use your personal e-mail address here, which you will check personally. Important information will always be sent to your parents as well. Do not use an e-mail address owned by your parents here."
},
"mobile_number": {
"label": "Mobile number",
"help_text": "Your mobile number helps us to reach you in an emergency during the event, e.g. if you are alone with your group at a conference or similar. If you don't have a cell phone, you can leave the field blank."
},
"school": {
"label": "School",
"help_text": "Please enter the name of your school."
},
"school_place": {
"label": "School place",
"help_text": "Enter the place (city) where your school is located."
},
"school_class": {
"label": "School class",
"help_text": "Please enter the class you are in (e.g. 8a)."
}
}
},
"guardians": {
"title": "Legal guardians",
"counter": "Guardian {i}",
"add": "Add guardian",
"fields": {
"first_name": {
"label": "Guardian's first name",
"help_text": "Please enter the first name of the legal guardian who will fill in the registration with you and who can be reached during the event in an emergency."
},
"last_name": {
"label": "Guardian's last name",
"help_text": "Please enter the last name of the legal guardian who will fill in the registration with you and who can be reached during the event in an emergency."
},
"email": {
"label": "Guardian's email address"
},
"mobile_number": {
"label": "Guardian's mobile number",
"help_text": "We need the mobile phone number for emergencies if we urgently need to reach your parents during the event."
}
}
},
"additional": {
"title": "Additional information",
"fields": {
"medical_information": {
"label": "Medical information / intolerances",
"help_text": "If there are any medically important things we need to consider, e.g. when making food or to make sure you take prescribed medication, please enter it here."
}
}
},
"financial": {
"title": "Payment",
"help_text": {
"cost": "Real costs",
"max_cost": "Maximal payable amount",
"min_cost": "Minimal payable amount"
},
"fields": {
"payment_method": {
"label": "Payment method",
"help_text": "Please choose a payment method. The actual payment will be made after the registration."
},
"voucher_code": {
"label": "Voucher code",
"help_text": "If you have a voucher code, type it in here."
},
"amount": {
"label": "Amount paid by you (in €)"
}
}
},
"consent": {
"title": "Consent",
"fields": {
"retraction_consent": {
"label": "I confirm that the retraction of the registration is not possible anymore after {date}"
}
}
},
"confirm": {
"title": "Confirm",
"hint": "After this step, you won't be able to edit your registration.",
"fields": {
"comment": {
"label": "Other remarks",
"help_text": "You can write down any remarks you want to tell us here."
}
}
}
},
"rules": {
"email": {
"valid": "This is not a valid e-mail address"
},
"confirm_email": {
"no_match": "The e-mail addresses do not match"
},
"confirm_password": {
"no_match": "The passwords do not match"
},
"amount": {
"too_high": "The amount is higher than the maximal payable amount.",
"too_low": "The amount is lower than the minimal payable amount."
}
},
"help_text": {
"guardian": "For guardians",
"participant": "For participants"
}
}
}
}
}