aboutsummaryrefslogtreecommitdiff
path: root/resources
diff options
context:
space:
mode:
authorThomas Hackl <hackl@data-quest.de>2025-01-27 15:52:02 +0000
committerThomas Hackl <hackl@data-quest.de>2025-01-27 15:52:02 +0000
commit9b2411a078a279cb4e24c0cc2ca78c032ad55e94 (patch)
tree58a7cb651133c20280d1d7253276feb8a92e2e01 /resources
parente4bf27a6e37efa3d7fd5decabacfd2dc94823aa6 (diff)
Resolve "Fehler bei der Anmeldeset-Verwaltung"
Closes #5086 Merge request studip/studip!3823
Diffstat (limited to 'resources')
-rw-r--r--resources/assets/javascripts/bootstrap/admission.js19
-rw-r--r--resources/assets/javascripts/entry-admission.js1
-rw-r--r--resources/assets/javascripts/entry-base.js1
-rw-r--r--resources/assets/javascripts/lib/admission.js172
-rw-r--r--resources/assets/javascripts/studip-ui.js4
-rw-r--r--resources/assets/stylesheets/scss/admission.scss31
-rw-r--r--resources/vue/components/Quicksearch.vue3
-rw-r--r--resources/vue/components/StudipDialog.vue14
-rw-r--r--resources/vue/components/admission/AdmissionRuleConfig.vue20
-rw-r--r--resources/vue/components/admission/ConfigureCourseSet.vue37
-rw-r--r--resources/vue/components/admission/CourseMemberAdmission.vue7
-rw-r--r--resources/vue/components/admission/InstantCourseSet.vue102
-rw-r--r--resources/vue/components/admission/ParticipantRestrictedAdmission.vue37
-rw-r--r--resources/vue/components/admission/TimedAdmission.vue3
-rw-r--r--resources/vue/components/admission/ValidityTime.vue8
-rw-r--r--resources/vue/mixins/AdmissionRuleMixin.js2
16 files changed, 197 insertions, 264 deletions
diff --git a/resources/assets/javascripts/bootstrap/admission.js b/resources/assets/javascripts/bootstrap/admission.js
index c04ff24..2fff6cf 100644
--- a/resources/assets/javascripts/bootstrap/admission.js
+++ b/resources/assets/javascripts/bootstrap/admission.js
@@ -22,32 +22,15 @@ STUDIP.ready(function () {
components[ruleType] = result.default;
STUDIP.Vue.load().then(({ createApp }) => {
- createApp({
- el: container,
- components: components
- });
+ createApp({components}).mount(container);
});
});
}
});
- $(document).on('change', 'tr.course input', function() {
- STUDIP.Admission.toggleNotSavedAlert();
- });
-
$('a.userlist-delete-user').on('click', function() {
$(this).closest('tr').remove();
return false;
});
-
- $('#courseset-form .autosave').on('click', () => {
- STUDIP.Admission.autosaveCourseset();
- });
-
- STUDIP.ready(() => {
- $('#toggle-date-link').on('click', () => {
- $('#admissionrule-valid-date').toggleClass('hidden-js');
- });
- });
});
diff --git a/resources/assets/javascripts/entry-admission.js b/resources/assets/javascripts/entry-admission.js
deleted file mode 100644
index 5454d08..0000000
--- a/resources/assets/javascripts/entry-admission.js
+++ /dev/null
@@ -1 +0,0 @@
-import "./bootstrap/admission.js"
diff --git a/resources/assets/javascripts/entry-base.js b/resources/assets/javascripts/entry-base.js
index 2210471..db3d1f6 100644
--- a/resources/assets/javascripts/entry-base.js
+++ b/resources/assets/javascripts/entry-base.js
@@ -78,6 +78,7 @@ import "./bootstrap/oer.js"
import "./bootstrap/courseware.js"
import "./bootstrap/external_pages.js"
import "./bootstrap/vips.js"
+import "./bootstrap/admission.js"
import "./mvv_course_wizard.js"
import "./mvv.js"
diff --git a/resources/assets/javascripts/lib/admission.js b/resources/assets/javascripts/lib/admission.js
index 8c0413a..c735cb2 100644
--- a/resources/assets/javascripts/lib/admission.js
+++ b/resources/assets/javascripts/lib/admission.js
@@ -2,7 +2,6 @@
* Anmeldeverfahren und -sets
* ------------------------------------------------------------------------ */
import { $gettext } from './gettext';
-import Dialog from './dialog.js';
const Admission = {
@@ -46,143 +45,6 @@ const Admission = {
return false;
},
- configureRule: function(ruleType, targetUrl, ruleId) {
- var urlparts = targetUrl.split('?');
- targetUrl = urlparts[0] + '/' + ruleType;
- if (urlparts[1]) {
- targetUrl += '?' + urlparts[1];
- }
-
- Dialog.fromURL(targetUrl, {
- method: 'post',
- size: 'auto',
- title: $gettext('Anmelderegel konfigurieren'),
- id: 'configurerule',
- data: { ruleId: ruleId, rules: _.map($('#rules input[name="rules[]"]'), 'value') }
- });
-
- return false;
- },
-
- selectRuleType: function(source) {
- Dialog.fromURL(source, {
- title: $gettext('Anmelderegel konfigurieren'),
- size: 'auto',
- data: { rules: _.map($('#rules input[name="rules[]"]'), 'value') },
- method: 'post',
- id: 'configurerule'
- });
- return false;
- },
-
- saveRule: function(ruleId, targetId, targetUrl) {
- if ($('#action').val() !== 'cancel') {
- $.ajax({
- type: 'post',
- url: targetUrl,
- data: $('#ruleform').serialize(),
- dataType: 'html',
- success: function(data) {
- if (data !== '') {
- var result = '';
- if ($('#norules').length > 0) {
- $('#norules').remove();
- $('#' + targetId).prepend('<div id="rulelist"></div>');
- }
- result += data;
- if ($('#rule_' + ruleId).length !== 0) {
- $('#rule_' + ruleId).replaceWith(result);
- } else {
- $('#rulelist').append(result);
- }
- }
- },
- error: function(jqXHR, textStatus, errorThrown) {
- alert('Status: ' + textStatus + '\nError: ' + errorThrown);
- }
- });
- }
- Admission.closeDialog('configurerule');
- Admission.toggleNotSavedAlert();
- return false;
- },
-
- removeRule: function(targetId, containerId) {
- var parent = $('#' + targetId).parent();
- $('#' + targetId).remove();
- if (parent.children('div').length === 0) {
- parent.remove();
- var norules = $gettext('Sie haben noch keine Anmelderegeln festgelegt.');
- $('#' + containerId).prepend('<span id="norules">' + '<i>' + norules + '</i></span>');
- }
- Admission.toggleNotSavedAlert();
- },
-
- toggleRuleDescription: function(targetId) {
- $('#' + targetId).toggle();
- return false;
- },
-
- toggleDetails: function(arrowId, detailId) {
- var oldSrc = $('#' + arrowId).attr('src');
- var newSrc = $('#' + arrowId).attr('rel');
- $('#' + arrowId).attr('src', newSrc);
- $('#' + arrowId).attr('rel', oldSrc);
- $('#' + detailId).slideToggle();
- return false;
- },
-
- /**
- *
- * @param String ruleId The rule to save.
- * @param String errorTarget Target element ID where error messages will be
- * shown.
- * @param String validateUrl URL to call for validation.
- * @param String savedTarget Target element ID where the saved rule will be
- * displayed.
- * @param String saveUrl URL to save the rule.
- */
- checkAndSaveRule: function(ruleId, errorTarget, validateUrl, savedTarget, saveUrl) {
- if (Admission.validateRuleConfig(errorTarget, validateUrl)) {
- Admission.saveRule(ruleId, savedTarget, saveUrl);
- Dialog.close({ id: 'configurerule' });
- }
- return false;
- },
-
- validateRuleConfig: function(containerId, targetUrl) {
- var valid = true;
- var error = $.ajax({
- type: 'post',
- async: false,
- url: targetUrl,
- data: $('#ruleform').serialize(),
- dataType: 'html',
-
- error: function(jqXHR, textStatus, errorThrown) {
- alert('Status: ' + textStatus + '\nError: ' + errorThrown);
- }
- }).responseText;
- error = error.replace(/(\r\n|\n|\r)/gm, '');
- if ($.trim(error) != '') {
- $('#' + containerId).html(error);
- valid = false;
- }
- return valid;
- },
-
- removeUserFromUserlist: function(userId) {
- var parent = $('#user_' + userId).parent();
- $('#user_' + userId).remove();
- if (parent.children('li').length === 0) {
- var nousers = $gettext('Sie haben noch niemanden hinzugefügt.');
- $(parent)
- .parent()
- .append('<span id="nousers">' + '<i>' + nousers + '</i></span>');
- }
- return false;
- },
-
updateInstitutes: function(elementId, instURL, courseURL, mode) {
if (elementId !== '') {
var query = '';
@@ -208,26 +70,6 @@ const Admission = {
}
},
- checkRuleActivation: function(target) {
- var form = $('#' + target);
- var globalActivation = form.find('input[name=enabled]');
- if (globalActivation.prop('checked')) {
- $('#activation').show();
- if (form.find('input[name=activated]:checked').val() === 'studip') {
- $('#institutes_activation').hide();
- } else {
- $('#institutes_activation').show();
- }
- } else {
- $('#activation').hide();
- $('#institutes_activation').hide();
- }
- },
-
- closeDialog: function(elementId) {
- $('#' + elementId).remove();
- },
-
checkUncheckAll: function(inputName, mode) {
switch (mode) {
case 'check':
@@ -251,20 +93,6 @@ const Admission = {
toggleNotSavedAlert: function() {
$('.hidden-alert').show();
- },
-
- autosaveCourseset: function() {
- $.post({
- url: $('#courseset-form').attr('action'),
- data: $('#courseset-form').serialize() + '&submit=1',
- dataType: 'html',
- success: function() {
- $('.hidden-alert').hide();
- },
- error: function(jqXHR, textStatus, errorThrown) {
- alert('Status: ' + textStatus + '\nError: ' + errorThrown);
- }
- });
}
};
diff --git a/resources/assets/javascripts/studip-ui.js b/resources/assets/javascripts/studip-ui.js
index d6483f3..f563b31 100644
--- a/resources/assets/javascripts/studip-ui.js
+++ b/resources/assets/javascripts/studip-ui.js
@@ -11,7 +11,9 @@ import RestrictedDatesHelper from './lib/RestrictedDatesHelper';
$.widget( "ui.dialog", $.ui.dialog, {
_allowInteraction: function( event ) {
- return hasParentWhich(isCKBodyWrapper)(event.target) || this._super( event );
+ return hasParentWhich(isCKBodyWrapper)(event.target)
+ || event.target.closest('.studip-dialog') !== null
+ || this._super( event );
},
});
diff --git a/resources/assets/stylesheets/scss/admission.scss b/resources/assets/stylesheets/scss/admission.scss
index d9d978c..50fce65 100644
--- a/resources/assets/stylesheets/scss/admission.scss
+++ b/resources/assets/stylesheets/scss/admission.scss
@@ -1,17 +1,3 @@
-#rulelist div.admissionrule {
- display: list-item;
- list-style-type: disc;
- margin-left: 25px;
-}
-
-#toggle-date-container {
- margin-top: 10px;
-
- img, svg {
- vertical-align: text-bottom;
- }
-}
-
.hover_box {
div {
display: inline;
@@ -88,23 +74,6 @@ form.default {
}
}
-#userlists {
- div {
- margin-bottom: 10px;
-
- a {
- &.userlist-action {
- margin-left: 2px;
- margin-right: 2px;
- }
-
- img {
- vertical-align: bottom;
- }
- }
- }
-}
-
form {
fieldset {
section {
diff --git a/resources/vue/components/Quicksearch.vue b/resources/vue/components/Quicksearch.vue
index 1a61513..9177ae5 100644
--- a/resources/vue/components/Quicksearch.vue
+++ b/resources/vue/components/Quicksearch.vue
@@ -32,7 +32,7 @@
<script>
export default {
name: 'quicksearch',
- emits: ['update:modelValue'],
+ emits: ['update:modelValue', 'input'],
props: {
searchtype: {
type: String,
@@ -125,6 +125,7 @@ export default {
this.results = [];
this.$emit('update:modelValue', this.returnValue, this.inputValue);
+ this.$emit('input', this.returnValue, this.inputValue);
if (!this.keepValue) {
this.inputValue = '';
diff --git a/resources/vue/components/StudipDialog.vue b/resources/vue/components/StudipDialog.vue
index ab42f48..94f95ed 100644
--- a/resources/vue/components/StudipDialog.vue
+++ b/resources/vue/components/StudipDialog.vue
@@ -1,7 +1,7 @@
<template>
<Teleport to="body">
<focus-trap v-model="trap">
- <div class="studip-dialog" @keydown.esc="closeDialog">
+ <div class="studip-dialog" @keydown.esc="closeDialog" :style="{zIndex: zIndex}">
<transition name="dialog-fade">
<div class="studip-dialog-backdrop" v-if="true">
<vue-resizeable
@@ -170,6 +170,8 @@ export default {
handlers: ["r", "rb", "b", "lb", "l", "lt", "t", "rt"],
fit: false,
footerHeight: 68,
+
+ zIndex: null,
};
},
computed: {
@@ -279,6 +281,16 @@ export default {
this.$refs.buttonB.focus();
});
}
+ },
+ created() {
+ const maxZIndex = Array.from(document.querySelectorAll('.studip-dialog')).reduce(
+ (acc, el) => {
+ const style = getComputedStyle(el);
+ return Math.max(acc, Number.parseInt(style.zIndex, 10));
+ },
+ 1
+ );
+ this.zIndex = maxZIndex + 1;
}
};
</script>
diff --git a/resources/vue/components/admission/AdmissionRuleConfig.vue b/resources/vue/components/admission/AdmissionRuleConfig.vue
index 921a6c2..d6d6e65 100644
--- a/resources/vue/components/admission/AdmissionRuleConfig.vue
+++ b/resources/vue/components/admission/AdmissionRuleConfig.vue
@@ -1,5 +1,5 @@
<template>
- <studip-dialog v-if="component !== null"
+ <studip-dialog v-if="useDialog && component !== null"
:title="$gettext('Anmelderegel bearbeiten')"
:close-text="$gettext('Abbrechen')"
@close="cancel"
@@ -25,6 +25,18 @@
</button>
</template>
</studip-dialog>
+ <div v-if="!useDialog && component !== null">
+ <studip-message-box v-if="invalidData?.length"
+ type="error"
+ :details="invalidData"
+ :hide-close="true"
+ :hide-details="false"
+ :aria-description="errorText"
+ role="alert">
+ {{ $gettext('Es sind ungültige Daten angegeben worden:') }}
+ </studip-message-box>
+ <component :is="component" v-bind="props" @submit="submit" @error="error"></component>
+ </div>
</template>
<script>
@@ -32,7 +44,7 @@ import {shallowRef} from "vue";
export default {
name: 'AdmissionRuleConfig',
- emits: ['cancel', 'submit'],
+ emits: ['cancel', 'submit', 'error'],
props: {
type: {
type: String,
@@ -45,6 +57,10 @@ export default {
assignedRuleTypes: {
type: Array,
default: () => []
+ },
+ useDialog: {
+ type: Boolean,
+ default: true
}
},
data() {
diff --git a/resources/vue/components/admission/ConfigureCourseSet.vue b/resources/vue/components/admission/ConfigureCourseSet.vue
index 226de37..8bd46f3 100644
--- a/resources/vue/components/admission/ConfigureCourseSet.vue
+++ b/resources/vue/components/admission/ConfigureCourseSet.vue
@@ -327,7 +327,7 @@
</button>
<button class="button cancel"
type="button"
- data-dialog="close"
+ data-dialog-close
@click.prevent="cancel"
>
{{ $gettext('Abbrechen') }}
@@ -382,6 +382,10 @@ export default {
myUserLists: {
type: Array,
default: () => []
+ },
+ instantCourseSetView: {
+ type: Boolean,
+ default: false
}
},
data() {
@@ -413,7 +417,7 @@ export default {
computed: {
isStorable() {
return this.name !== ''
- && this.institutes.length > 0
+ && (this.courseSetId !== '' || this.courseSetId === '' && this.institutes.length > 0)
&& this.rules.length > 0;
},
hasConfigurableCourses() {
@@ -498,7 +502,7 @@ export default {
this.showRuleConfig = true;
},
addRuleConfiguration(data) {
- if (!this.ruleId) {
+ if (!this.ruleId || this.ruleId === data.type + '_') {
STUDIP.jsonapi.withPromises().post(
'admission-rules/' + data.type,
{
@@ -566,7 +570,7 @@ export default {
}
},
addInstitute(returnValue, inputValue) {
- if (!this.institutes.some(i => i.id === returnValue)) {
+ if (inputValue && !this.institutes.some(i => i.id === returnValue)) {
this.institutes.push({ id: returnValue, name: inputValue });
}
},
@@ -594,7 +598,11 @@ export default {
{ data: data }
).then(() => {
this.$refs.courseSetForm.dataset.secure = 'false';
- window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset');
+ if (!this.instantCourseSetView) {
+ window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset');
+ } else {
+ window.location.reload();
+ }
});
} else {
@@ -604,28 +612,31 @@ export default {
{ data: data}
).then(() => {
this.$refs.courseSetForm.dataset.secure = 'false';
- window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset');
+ if (!this.instantCourseSetView) {
+ window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset');
+ } else {
+ window.location.reload();
+ }
});
}
},
cancel() {
- window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset');
+ if (!this.instantCourseSetView) {
+ window.location = STUDIP.URLHelper.getURL('dispatch.php/admission/courseset');
+ }
},
- configureCourses()
- {
+ configureCourses() {
STUDIP.Dialog.fromURL(
STUDIP.URLHelper.getURL('dispatch.php/admission/courseset/configure_courses/' + this.courseSetId)
);
},
- getApplicants()
- {
+ getApplicants() {
STUDIP.Dialog.fromURL(
STUDIP.URLHelper.getURL('dispatch.php/admission/courseset/applications_list/' + this.courseSetId)
);
},
- messageApplicants()
- {
+ messageApplicants() {
STUDIP.Dialog.fromURL(
STUDIP.URLHelper.getURL('dispatch.php/admission/courseset/applicants_message/' + this.courseSetId)
);
diff --git a/resources/vue/components/admission/CourseMemberAdmission.vue b/resources/vue/components/admission/CourseMemberAdmission.vue
index 9e689c5..3684eb3 100644
--- a/resources/vue/components/admission/CourseMemberAdmission.vue
+++ b/resources/vue/components/admission/CourseMemberAdmission.vue
@@ -24,8 +24,7 @@
<quicksearch v-if="courseSearch !== null"
:searchtype="courseSearch"
name="course"
- :key="NaN"
- @input="addCourse"
+ @update:model-value="addCourse"
id="csearch"
ref="courseSearch"></quicksearch>
<ul v-if="courseList.length > 0">
@@ -89,7 +88,7 @@ export default {
return this.invalidData.length === 0;
},
},
- mounted() {
+ created() {
// Get a new rule instance so we can use quicksearch.
if (!this.id || this.id === '') {
STUDIP.jsonapi.withPromises().post('admission-rules/CourseMemberAdmission', {
@@ -97,7 +96,7 @@ export default {
data: {
attributes: {
payload: {
- mode: 0,
+ modus: 0,
courses: [],
message: ''
}
diff --git a/resources/vue/components/admission/InstantCourseSet.vue b/resources/vue/components/admission/InstantCourseSet.vue
new file mode 100644
index 0000000..ec555c6
--- /dev/null
+++ b/resources/vue/components/admission/InstantCourseSet.vue
@@ -0,0 +1,102 @@
+<template>
+ <form v-if="!working" class="default">
+ <section v-for="(type, index) in ruleTypes" :key="index">
+ <admission-rule-config :type="type"
+ :use-dialog="false"
+ @submit="ruleData"></admission-rule-config>
+ </section>
+ <section>
+ <label class="caption">
+ {{ $gettext("Name für diese Anmelderegel") }}
+ <input type="text" name="instant_course_set_name" size="70" v-model="name">
+ </label>
+ </section>
+ <footer data-dialog-button>
+ <button class="button accept" @click.prevent="triggerRules">
+ {{ $gettext('Speichern') }}
+ </button>
+ <button class="button cancel" data-dialog-close>
+ {{ $gettext('Abbrechen') }}
+ </button>
+ </footer>
+ </form>
+</template>
+
+<script>
+import AdmissionRuleConfig from './AdmissionRuleConfig';
+
+export default {
+ name: 'InstantCourseSet',
+ components: { AdmissionRuleConfig },
+ props: {
+ ruleTypes: {
+ type: Array,
+ required: true
+ },
+ courseSetName: {
+ type: String,
+ required: true
+ },
+ courseId: {
+ type: String,
+ required: true
+ }
+ },
+ data() {
+ return {
+ name: this.courseSetName,
+ rules: [],
+ working: false
+ }
+ },
+ methods: {
+ ruleData(data) {
+ this.working = true;
+ this.rules.push(data);
+
+ // Check if all rultTypes have some data. If yes, the whole courseset can be stored.
+ let canStore = true;
+ for (let i = 0 ; i < this.ruleTypes.length ; i++) {
+ if (this.rules.filter(rule => rule.type === this.ruleTypes[i]).length === 0) {
+ canStore = false;
+ }
+ }
+
+ if (canStore) {
+ this.store();
+ }
+ },
+ triggerRules() {
+ STUDIP.eventBus.emit('getRuleConfiguration');
+ },
+ store() {
+ const data = {
+ data: {
+ attributes: {
+ name: this.name,
+ private: true,
+ infotext: '',
+ institutes: [],
+ courses: [ this.courseId ],
+ rules: this.rules.map((rule) => { return { attributes: rule } } ),
+ userlists: []
+ }
+ }
+ };
+
+ STUDIP.jsonapi.withPromises().post(
+ 'course-sets',
+ { data: data }
+ ).then(() => {
+ STUDIP.Report.success(this.$gettext('Die Zugangsberechtigungen wurden gespeichert.'));
+ window.location = STUDIP.URLHelper.getURL('dispatch.php/course/admission', {cid: this.courseId});
+ });
+ }
+ },
+ created() {
+ for (let i = 0 ; i < this.ruleTypes.length ; i++) {
+ this.rules[this.ruleTypes[i]] = {};
+ }
+ }
+}
+</script>
diff --git a/resources/vue/components/admission/ParticipantRestrictedAdmission.vue b/resources/vue/components/admission/ParticipantRestrictedAdmission.vue
index 9f75b9a..96b6cfb 100644
--- a/resources/vue/components/admission/ParticipantRestrictedAdmission.vue
+++ b/resources/vue/components/admission/ParticipantRestrictedAdmission.vue
@@ -1,4 +1,4 @@
-<template>
+ <template>
<form class="default">
<section>
<label>
@@ -16,7 +16,7 @@
<section v-if="!fcfsAllowed || !fcfsEnabled">
<label>
{{ $gettext('Zeitpunkt der automatischen Platzverteilung') }}
- <datetimepicker v-if="loaded" :value="distributionTime" v-model="distributionTime"></datetimepicker>
+ <datetimepicker v-model="distributionTime"></datetimepicker>
</label>
</section>
</form>
@@ -24,17 +24,17 @@
<script>
import { AdmissionRuleMixin } from '../../mixins/AdmissionRuleMixin';
-import Datetimepicker from '../Datetimepicker.vue';
+import datetimepicker from '../Datetimepicker.vue';
import StudipTooltipIcon from '../StudipTooltipIcon.vue';
export default {
name: 'ParticipantRestrictedAdmission',
- components: { StudipTooltipIcon, Datetimepicker },
+ components: { StudipTooltipIcon, datetimepicker },
mixins: [AdmissionRuleMixin],
props: {
distribution: {
type: Number,
- default: Math.floor(new Date().getTime() / 1000 + 86400)
+ default: 0
},
fcfs: {
type: Boolean,
@@ -54,8 +54,7 @@ export default {
messageText: this.message,
fcfsAllowed: true,
fcfsEnabled: this.distributionTime === 0,
- distributionTime: this.distribution,
- loaded: false
+ distributionTime: this.distribution !== 0 ? this.distribution : Math.floor(Date.now() / 1000 + 7 * 86400)
}
},
computed: {
@@ -78,13 +77,23 @@ export default {
? data.attributes.payload['distribution-time']
: Math.floor(Date.now() / 1000 + 7 * 86400);
this.fcfsEnabled = data.attributes.payload['distribution-time'] === 0;
- this.loaded = true;
- }
- },
- created() {
- if (!this.id) {
- this.distributionTime = Math.floor(new Date().getTime() / 1000 + 86400);
- this.loaded = true;
+ },
+ validate() {
+ // Earliest possible date for seat distribution is 2 hours from now.
+ const earliest = new Date();
+ earliest.setHours( earliest.getHours() + 2);
+
+ if (!this.fcfsEnabled && this.distributionTime <= Math.floor(earliest.getTime() / 1000)) {
+ this.invalidData.push(
+ this.$gettext(
+ 'Geben Sie für die Platzverteilung ein Datum an, das weiter in der Zukunft liegt. ' +
+ 'Das frühestmögliche Datum ist %{earliest}.',
+ {earliest: earliest.toLocaleString('de-de')}
+ )
+ );
+ }
+
+ return this.invalidData.length === 0;
}
}
}
diff --git a/resources/vue/components/admission/TimedAdmission.vue b/resources/vue/components/admission/TimedAdmission.vue
index ebdc397..2437d7e 100644
--- a/resources/vue/components/admission/TimedAdmission.vue
+++ b/resources/vue/components/admission/TimedAdmission.vue
@@ -23,9 +23,10 @@
<script>
import { AdmissionRuleMixin } from '../../mixins/AdmissionRuleMixin';
-
+import datetimepicker from "../Datetimepicker.vue";
export default {
name: 'TimedAdmission',
+ components: { datetimepicker },
mixins: [ AdmissionRuleMixin ],
props: {
start: {
diff --git a/resources/vue/components/admission/ValidityTime.vue b/resources/vue/components/admission/ValidityTime.vue
index 067567c..32efd04 100644
--- a/resources/vue/components/admission/ValidityTime.vue
+++ b/resources/vue/components/admission/ValidityTime.vue
@@ -16,24 +16,24 @@
<section v-if="configureTime" class="col-3">
<label>
{{ $gettext('Diese Regel gilt von') }}
- <datetimepicker :value="startTime"></datetimepicker>
+ <datetimepicker v-model="startTime"></datetimepicker>
</label>
</section>
<section v-if="configureTime" class="col-3">
<label>
{{ $gettext('bis') }}
- <datetimepicker :value="endTime"></datetimepicker>
+ <datetimepicker v-model="endTime"></datetimepicker>
</label>
</section>
</div>
</template>
<script>
-import Datetimepicker from '../Datetimepicker.vue';
+import datetimepicker from '../Datetimepicker.vue';
export default {
name: 'ValidityTime',
- components: { Datetimepicker },
+ components: { datetimepicker },
props: {
start: {
type: Number,
diff --git a/resources/vue/mixins/AdmissionRuleMixin.js b/resources/vue/mixins/AdmissionRuleMixin.js
index 0badb1a..80f6ec5 100644
--- a/resources/vue/mixins/AdmissionRuleMixin.js
+++ b/resources/vue/mixins/AdmissionRuleMixin.js
@@ -42,7 +42,7 @@ export const AdmissionRuleMixin = {
}
}
},
- mounted() {
+ created() {
if (this.id && this.id !== '' && !this.ruleData) {
this.loadRuleData();
}