mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-10-12 15:04:04 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec59af8d5f |
@@ -22,6 +22,7 @@ import OtherLvPlan from "../../components/Cis/LvPlan/OtherLvPlan.js";
|
|||||||
|
|
||||||
import ApiRouteInfo from '../../api/factory/routeinfo.js';
|
import ApiRouteInfo from '../../api/factory/routeinfo.js';
|
||||||
import {capitalize} from "../../helpers/StringHelpers.js";
|
import {capitalize} from "../../helpers/StringHelpers.js";
|
||||||
|
import { getTodayISO, toDateTime } from "../../helpers/DateHelpers.js";
|
||||||
|
|
||||||
const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
||||||
const isMobile = window.matchMedia("(max-width: 767px)").matches;
|
const isMobile = window.matchMedia("(max-width: 767px)").matches;
|
||||||
@@ -88,7 +89,7 @@ const router = VueRouter.createRouter({
|
|||||||
params: { // in this case always populate other params since they are not optional
|
params: { // in this case always populate other params since they are not optional
|
||||||
ort_kurzbz: to.params.ort_kurzbz,
|
ort_kurzbz: to.params.ort_kurzbz,
|
||||||
mode: isMobile ? DEFAULT_MODE_RAUMINFO_MOBILE : DEFAULT_MODE_RAUMINFO_DESKTOP,
|
mode: isMobile ? DEFAULT_MODE_RAUMINFO_MOBILE : DEFAULT_MODE_RAUMINFO_DESKTOP,
|
||||||
focus_date: new Date().toISOString().split("T")[0]
|
focus_date: getTodayISO()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -107,8 +108,7 @@ const router = VueRouter.createRouter({
|
|||||||
: (isMobile ? DEFAULT_MODE_RAUMINFO_MOBILE : DEFAULT_MODE_RAUMINFO_DESKTOP);
|
: (isMobile ? DEFAULT_MODE_RAUMINFO_MOBILE : DEFAULT_MODE_RAUMINFO_DESKTOP);
|
||||||
|
|
||||||
// default to today date if not provided
|
// default to today date if not provided
|
||||||
const d = new Date(route.params.focus_date)
|
const focus_date = toDateTime(route.params.focus_date) ? route.params.focus_date : getTodayISO();
|
||||||
const focus_date = !isNaN(d) ? route.params.focus_date : new Date().toISOString().split("T")[0];
|
|
||||||
|
|
||||||
// for consistency reasons format the props into one object but actually use a new name to we dont collide with
|
// for consistency reasons format the props into one object but actually use a new name to we dont collide with
|
||||||
// existing viewData declaration written from codeigniter 3 into routerview tag
|
// existing viewData declaration written from codeigniter 3 into routerview tag
|
||||||
@@ -127,7 +127,7 @@ const router = VueRouter.createRouter({
|
|||||||
name: "RoomInformation",
|
name: "RoomInformation",
|
||||||
params: {
|
params: {
|
||||||
mode: to.params.mode || DEFAULT_MODE_RAUMINFO,
|
mode: to.params.mode || DEFAULT_MODE_RAUMINFO,
|
||||||
focus_date: to.params.focus_date || new Date().toISOString().split("T")[0],
|
focus_date: to.params.focus_date || getTodayISO(),
|
||||||
ort_kurzbz: route.params.ort_kurzbz
|
ort_kurzbz: route.params.ort_kurzbz
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import BsModal from '../../Bootstrap/Modal.js';
|
|||||||
import VueDatePicker from '../../vueDatepicker.js.php';
|
import VueDatePicker from '../../vueDatepicker.js.php';
|
||||||
import ApiAbgabe from '../../../api/factory/abgabe.js'
|
import ApiAbgabe from '../../../api/factory/abgabe.js'
|
||||||
import { getDateStyleClass } from "./getDateStyleClass.js";
|
import { getDateStyleClass } from "./getDateStyleClass.js";
|
||||||
import {compareISODateValues, formatDateTime, formatISODate, getViennaTodayISO} from "./dateUtils.js";
|
import { compareISODateValues, formatDate, formatDateTime, getTodayISO } from "../../../helpers/DateHelpers.js";
|
||||||
|
|
||||||
|
|
||||||
export const AbgabeMitarbeiterDetail = {
|
export const AbgabeMitarbeiterDetail = {
|
||||||
@@ -174,7 +174,7 @@ export const AbgabeMitarbeiterDetail = {
|
|||||||
'fixtermin': false,
|
'fixtermin': false,
|
||||||
'invertedFixtermin': true,
|
'invertedFixtermin': true,
|
||||||
'kurzbz': '', // todo kurzbz textfield value vorschlag für qualgates
|
'kurzbz': '', // todo kurzbz textfield value vorschlag für qualgates
|
||||||
'datum': getViennaTodayISO(),
|
'datum': getTodayISO(),
|
||||||
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
||||||
'beurteilungsnotiz': '',
|
'beurteilungsnotiz': '',
|
||||||
'upload_allowed': false,
|
'upload_allowed': false,
|
||||||
@@ -351,9 +351,7 @@ export const AbgabeMitarbeiterDetail = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
formatDate(dateParam) {
|
formatDate,
|
||||||
return formatISODate(dateParam)
|
|
||||||
},
|
|
||||||
openCreateNewAbgabeModal() {
|
openCreateNewAbgabeModal() {
|
||||||
if(this.projektarbeit?.betreuerart_kurzbz == 'Zweitbegutachter') {
|
if(this.projektarbeit?.betreuerart_kurzbz == 'Zweitbegutachter') {
|
||||||
// maybe alert that this is not allowed or smth
|
// maybe alert that this is not allowed or smth
|
||||||
@@ -370,7 +368,7 @@ export const AbgabeMitarbeiterDetail = {
|
|||||||
'fixtermin': false,
|
'fixtermin': false,
|
||||||
'invertedFixtermin': true,
|
'invertedFixtermin': true,
|
||||||
'kurzbz': '',
|
'kurzbz': '',
|
||||||
'datum': getViennaTodayISO(),
|
'datum': getTodayISO(),
|
||||||
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
||||||
'beurteilungsnotiz': '',
|
'beurteilungsnotiz': '',
|
||||||
'upload_allowed': typ.upload_allowed_default,
|
'upload_allowed': typ.upload_allowed_default,
|
||||||
@@ -404,7 +402,7 @@ export const AbgabeMitarbeiterDetail = {
|
|||||||
'fixtermin': false,
|
'fixtermin': false,
|
||||||
'invertedFixtermin': true,
|
'invertedFixtermin': true,
|
||||||
'kurzbz': '',
|
'kurzbz': '',
|
||||||
'datum': getViennaTodayISO(),
|
'datum': getTodayISO(),
|
||||||
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
||||||
'beurteilungsnotiz': '',
|
'beurteilungsnotiz': '',
|
||||||
'upload_allowed': false,
|
'upload_allowed': false,
|
||||||
@@ -603,7 +601,7 @@ export const AbgabeMitarbeiterDetail = {
|
|||||||
'fixtermin': false,
|
'fixtermin': false,
|
||||||
'invertedFixtermin': true,
|
'invertedFixtermin': true,
|
||||||
'kurzbz': '',
|
'kurzbz': '',
|
||||||
'datum': getViennaTodayISO(),
|
'datum': getTodayISO(),
|
||||||
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
||||||
'beurteilungsnotiz': '',
|
'beurteilungsnotiz': '',
|
||||||
'upload_allowed': typ.upload_allowed_default,
|
'upload_allowed': typ.upload_allowed_default,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import BsModal from '../../Bootstrap/Modal.js';
|
|||||||
import VueDatePicker from '../../vueDatepicker.js.php';
|
import VueDatePicker from '../../vueDatepicker.js.php';
|
||||||
import ApiAbgabe from '../../../api/factory/abgabe.js'
|
import ApiAbgabe from '../../../api/factory/abgabe.js'
|
||||||
import FhcOverlay from "../../Overlay/FhcOverlay.js";
|
import FhcOverlay from "../../Overlay/FhcOverlay.js";
|
||||||
import { formatISODate, getViennaTodayISO } from "./dateUtils.js";
|
import { formatDate, getTodayISO } from "../../../helpers/DateHelpers.js";
|
||||||
import { validateThesisTitle } from './titleValidation.js'
|
import { validateThesisTitle } from './titleValidation.js'
|
||||||
|
|
||||||
|
|
||||||
@@ -248,9 +248,7 @@ export const AbgabeStudentDetail = {
|
|||||||
|
|
||||||
window.open(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + url)
|
window.open(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + url)
|
||||||
},
|
},
|
||||||
formatDate(dateParam) {
|
formatDate,
|
||||||
return formatISODate(dateParam)
|
|
||||||
},
|
|
||||||
async upload(termin) {
|
async upload(termin) {
|
||||||
|
|
||||||
if (! await this.validate(termin))
|
if (! await this.validate(termin))
|
||||||
@@ -286,7 +284,7 @@ export const AbgabeStudentDetail = {
|
|||||||
if(res.meta.status == "success") {
|
if(res.meta.status == "success") {
|
||||||
this.$fhcAlert.alertSuccess(this.$capitalize(this.$p.t('abgabetool/c4fileUploadSuccessv3')))
|
this.$fhcAlert.alertSuccess(this.$capitalize(this.$p.t('abgabetool/c4fileUploadSuccessv3')))
|
||||||
|
|
||||||
termin.abgabedatum = getViennaTodayISO();
|
termin.abgabedatum = getTodayISO();
|
||||||
if(res?.data?.signatur !== undefined) {
|
if(res?.data?.signatur !== undefined) {
|
||||||
termin.signatur = res.data.signatur
|
termin.signatur = res.data.signatur
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import AbgabeterminStatusLegende from "./StatusLegende.js";
|
import AbgabeterminStatusLegende from "./StatusLegende.js";
|
||||||
import {formatDateTime} from "./dateUtils.js";
|
import { formatDateTime } from "../../../helpers/DateHelpers.js";
|
||||||
|
|
||||||
export const AbgabeStudentTimeline = {
|
export const AbgabeStudentTimeline = {
|
||||||
name: "AbgabeStudentTimeline",
|
name: "AbgabeStudentTimeline",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import AbgabeStudentTimeline from "./AbgabeStudentTimeline.js";
|
|||||||
import { splitMailsHelper } from "../../../helpers/EmailHelpers.js"
|
import { splitMailsHelper } from "../../../helpers/EmailHelpers.js"
|
||||||
import { getDateStyleClass} from "./getDateStyleClass.js";
|
import { getDateStyleClass} from "./getDateStyleClass.js";
|
||||||
import { dateFilter } from '../../../tabulator/filters/DatesManual.js';
|
import { dateFilter } from '../../../tabulator/filters/DatesManual.js';
|
||||||
import { compareISODateValues, formatISODate, getViennaTodayISO, toViennaDate } from "./dateUtils.js";
|
import { compareISODateValues, formatDate, getNow, getTodayISO, toDateTime } from "../../../helpers/DateHelpers.js";
|
||||||
|
|
||||||
export const AbgabetoolAssistenz = {
|
export const AbgabetoolAssistenz = {
|
||||||
name: "AbgabetoolAssistenz",
|
name: "AbgabetoolAssistenz",
|
||||||
@@ -114,7 +114,7 @@ export const AbgabetoolAssistenz = {
|
|||||||
fixtermin: false,
|
fixtermin: false,
|
||||||
},
|
},
|
||||||
serienTermin: Vue.reactive({
|
serienTermin: Vue.reactive({
|
||||||
datum: getViennaTodayISO(),
|
datum: getTodayISO(),
|
||||||
bezeichnung: {
|
bezeichnung: {
|
||||||
paabgabetyp_kurzbz: 'zwischen',
|
paabgabetyp_kurzbz: 'zwischen',
|
||||||
bezeichnung: 'Zwischenabgabe'
|
bezeichnung: 'Zwischenabgabe'
|
||||||
@@ -643,7 +643,7 @@ export const AbgabetoolAssistenz = {
|
|||||||
upload_allowed: false,
|
upload_allowed: false,
|
||||||
fixtermin: false,
|
fixtermin: false,
|
||||||
}
|
}
|
||||||
this.serienEdit.datum = getViennaTodayISO()
|
this.serienEdit.datum = getTodayISO()
|
||||||
this.serienEdit.bezeichnung = this.abgabeTypeOptions.find(opt => opt.paabgabetyp_kurzbz === 'zwischen')
|
this.serienEdit.bezeichnung = this.abgabeTypeOptions.find(opt => opt.paabgabetyp_kurzbz === 'zwischen')
|
||||||
this.serienEdit.kurzbz = ''
|
this.serienEdit.kurzbz = ''
|
||||||
this.serienEdit.upload_allowed = false
|
this.serienEdit.upload_allowed = false
|
||||||
@@ -1091,23 +1091,9 @@ export const AbgabetoolAssistenz = {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const toLuxon = (val) => {
|
const rowDate = toDateTime(rowVal);
|
||||||
if (!val) return null;
|
const von = toDateTime(filterVal[0]);
|
||||||
let dt;
|
const bis = toDateTime(filterVal[1]);
|
||||||
if (val instanceof Date) {
|
|
||||||
dt = luxon.DateTime.fromJSDate(val);
|
|
||||||
} else if (typeof val === "string") {
|
|
||||||
dt = toViennaDate(val);
|
|
||||||
} else { // fallback
|
|
||||||
dt = luxon.DateTime.fromMillis(Number(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
return dt.isValid ? dt : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const rowDate = toLuxon(rowVal);
|
|
||||||
const von = toLuxon(filterVal[0]);
|
|
||||||
const bis = toLuxon(filterVal[1]);
|
|
||||||
|
|
||||||
// specific day
|
// specific day
|
||||||
if (von && !bis) {
|
if (von && !bis) {
|
||||||
@@ -1128,22 +1114,8 @@ export const AbgabetoolAssistenz = {
|
|||||||
|
|
||||||
const rowDate = rowVal.luxonDate;
|
const rowDate = rowVal.luxonDate;
|
||||||
|
|
||||||
const toLuxon = (val) => {
|
const von = toDateTime(filterVal[0]);
|
||||||
if (!val) return null;
|
const bis = toDateTime(filterVal[1]);
|
||||||
let dt;
|
|
||||||
if (val instanceof Date) {
|
|
||||||
dt = luxon.DateTime.fromJSDate(val);
|
|
||||||
} else if (typeof val === "string") {
|
|
||||||
dt = toViennaDate(val);
|
|
||||||
} else { // fallback
|
|
||||||
dt = luxon.DateTime.fromMillis(Number(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
return dt.isValid ? dt : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const von = toLuxon(filterVal[0]);
|
|
||||||
const bis = toLuxon(filterVal[1]);
|
|
||||||
|
|
||||||
// specific day
|
// specific day
|
||||||
if (von && !bis) {
|
if (von && !bis) {
|
||||||
@@ -1372,7 +1344,7 @@ export const AbgabetoolAssistenz = {
|
|||||||
|
|
||||||
},
|
},
|
||||||
checkAbgabetermineProjektarbeit(projekt) {
|
checkAbgabetermineProjektarbeit(projekt) {
|
||||||
const now = luxon.DateTime.now()
|
const now = getNow()
|
||||||
|
|
||||||
// calculate Abgabetermin time diff to now and assign last and next to projekt
|
// calculate Abgabetermin time diff to now and assign last and next to projekt
|
||||||
projekt.abgabetermine.forEach(termin => {
|
projekt.abgabetermine.forEach(termin => {
|
||||||
@@ -1387,7 +1359,7 @@ export const AbgabetoolAssistenz = {
|
|||||||
// while already looping through each termin, calculate datestyle beforehand
|
// while already looping through each termin, calculate datestyle beforehand
|
||||||
termin.dateStyle = getDateStyleClass(termin, this.notenOptions)
|
termin.dateStyle = getDateStyleClass(termin, this.notenOptions)
|
||||||
|
|
||||||
const date = toViennaDate(termin.datum).endOf('day')
|
const date = toDateTime(termin.datum).endOf('day')
|
||||||
termin.luxonDate = date
|
termin.luxonDate = date
|
||||||
termin.diffMs = date.toMillis() - now.toMillis(); // positive = future, negative = past
|
termin.diffMs = date.toMillis() - now.toMillis(); // positive = future, negative = past
|
||||||
|
|
||||||
@@ -1654,9 +1626,7 @@ export const AbgabetoolAssistenz = {
|
|||||||
getNotenFilterOptionLabel(option) {
|
getNotenFilterOptionLabel(option) {
|
||||||
return option.bezeichnung
|
return option.bezeichnung
|
||||||
},
|
},
|
||||||
formatDate(dateParam) {
|
formatDate,
|
||||||
return formatISODate(dateParam);
|
|
||||||
},
|
|
||||||
formAction(cell) {
|
formAction(cell) {
|
||||||
const actionButtons = document.createElement('div');
|
const actionButtons = document.createElement('div');
|
||||||
actionButtons.className = "d-flex gap-3";
|
actionButtons.className = "d-flex gap-3";
|
||||||
@@ -1851,9 +1821,7 @@ export const AbgabetoolAssistenz = {
|
|||||||
return str
|
return str
|
||||||
},
|
},
|
||||||
isPastDate(date) {
|
isPastDate(date) {
|
||||||
const deadline = luxon.DateTime.fromISO(date, { zone: 'Europe/Vienna' }).endOf('day');
|
return getNow() > toDateTime(date).endOf("day");
|
||||||
const nowInVienna = luxon.DateTime.now().setZone('Europe/Vienna');
|
|
||||||
return nowInVienna > deadline;
|
|
||||||
},
|
},
|
||||||
setDetailComponent(details){
|
setDetailComponent(details){
|
||||||
const pa = this.projektarbeiten.find(projektarbeit => projektarbeit.projektarbeit_id == details.projektarbeit_id)
|
const pa = this.projektarbeiten.find(projektarbeit => projektarbeit.projektarbeit_id == details.projektarbeit_id)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import FhcOverlay from "../../Overlay/FhcOverlay.js";
|
|||||||
import { getDateStyleClass } from "./getDateStyleClass.js";
|
import { getDateStyleClass } from "./getDateStyleClass.js";
|
||||||
import { dateFilter } from '../../../tabulator/filters/DatesManual.js';
|
import { dateFilter } from '../../../tabulator/filters/DatesManual.js';
|
||||||
import {splitMailsHelper} from "../../../helpers/EmailHelpers.js";
|
import {splitMailsHelper} from "../../../helpers/EmailHelpers.js";
|
||||||
import { formatISODate, getViennaTodayISO, toViennaDate } from "./dateUtils.js";
|
import { formatDate, getNow, getTodayISO, toDateTime } from "../../../helpers/DateHelpers.js";
|
||||||
|
|
||||||
export const AbgabetoolMitarbeiter = {
|
export const AbgabetoolMitarbeiter = {
|
||||||
name: "AbgabetoolMitarbeiter",
|
name: "AbgabetoolMitarbeiter",
|
||||||
@@ -54,7 +54,7 @@ export const AbgabetoolMitarbeiter = {
|
|||||||
allowedNotenOptions: null,
|
allowedNotenOptions: null,
|
||||||
notenOptionsNonFinal: null,
|
notenOptionsNonFinal: null,
|
||||||
serienTermin: Vue.reactive({
|
serienTermin: Vue.reactive({
|
||||||
datum: getViennaTodayISO(),
|
datum: getTodayISO(),
|
||||||
bezeichnung: {
|
bezeichnung: {
|
||||||
paabgabetyp_kurzbz: 'zwischen',
|
paabgabetyp_kurzbz: 'zwischen',
|
||||||
bezeichnung: 'Zwischenabgabe'
|
bezeichnung: 'Zwischenabgabe'
|
||||||
@@ -668,22 +668,8 @@ export const AbgabetoolMitarbeiter = {
|
|||||||
|
|
||||||
const rowDate = rowVal.luxonDate;
|
const rowDate = rowVal.luxonDate;
|
||||||
|
|
||||||
const toLuxon = (val) => {
|
const von = toDateTime(filterVal[0]);
|
||||||
if (!val) return null;
|
const bis = toDateTime(filterVal[1]);
|
||||||
let dt;
|
|
||||||
if (val instanceof Date) {
|
|
||||||
dt = luxon.DateTime.fromJSDate(val);
|
|
||||||
} else if (typeof val === "string") {
|
|
||||||
dt = toViennaDate(val);
|
|
||||||
} else { // fallback
|
|
||||||
dt = luxon.DateTime.fromMillis(Number(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
return dt.isValid ? dt : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const von = toLuxon(filterVal[0]);
|
|
||||||
const bis = toLuxon(filterVal[1]);
|
|
||||||
|
|
||||||
// specific day
|
// specific day
|
||||||
if (von && !bis) {
|
if (von && !bis) {
|
||||||
@@ -899,14 +885,14 @@ export const AbgabetoolMitarbeiter = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
checkAbgabetermineProjektarbeit(projekt) {
|
checkAbgabetermineProjektarbeit(projekt) {
|
||||||
const now = luxon.DateTime.now()
|
const now = getNow()
|
||||||
// calculate Abgabetermin time diff to now and assign last and next to projekt
|
// calculate Abgabetermin time diff to now and assign last and next to projekt
|
||||||
projekt.abgabetermine.forEach(termin => {
|
projekt.abgabetermine.forEach(termin => {
|
||||||
|
|
||||||
// while already looping through each termin, calculate datestyle beforehand
|
// while already looping through each termin, calculate datestyle beforehand
|
||||||
termin.dateStyle = getDateStyleClass(termin, this.notenOptions)
|
termin.dateStyle = getDateStyleClass(termin, this.notenOptions)
|
||||||
|
|
||||||
const date = toViennaDate(termin.datum).endOf('day')
|
const date = toDateTime(termin.datum).endOf('day')
|
||||||
termin.luxonDate = date
|
termin.luxonDate = date
|
||||||
termin.diffMs = date.toMillis() - now.toMillis(); // positive = future, negative = past
|
termin.diffMs = date.toMillis() - now.toMillis(); // positive = future, negative = past
|
||||||
|
|
||||||
@@ -1017,9 +1003,7 @@ export const AbgabetoolMitarbeiter = {
|
|||||||
getOptionLabelAbgabetyp(option){
|
getOptionLabelAbgabetyp(option){
|
||||||
return this.$p.t('abgabetool/c4paatyp' + option.paabgabetyp_kurzbz)
|
return this.$p.t('abgabetool/c4paatyp' + option.paabgabetyp_kurzbz)
|
||||||
},
|
},
|
||||||
formatDate(dateParam) {
|
formatDate,
|
||||||
return formatISODate(dateParam);
|
|
||||||
},
|
|
||||||
undoSelection(cell) {
|
undoSelection(cell) {
|
||||||
// checks if cells row is selected and unselects -> imitates columns which dont trigger row selection
|
// checks if cells row is selected and unselects -> imitates columns which dont trigger row selection
|
||||||
// but actually just revert it after the fact
|
// but actually just revert it after the fact
|
||||||
@@ -1104,9 +1088,7 @@ export const AbgabetoolMitarbeiter = {
|
|||||||
return str
|
return str
|
||||||
},
|
},
|
||||||
isPastDate(date) {
|
isPastDate(date) {
|
||||||
const deadline = luxon.DateTime.fromISO(date, { zone: 'Europe/Vienna' }).endOf('day');
|
return getNow() > toDateTime(date).endOf("day");
|
||||||
const nowInVienna = luxon.DateTime.now().setZone('Europe/Vienna');
|
|
||||||
return nowInVienna > deadline;
|
|
||||||
},
|
},
|
||||||
setDetailComponent(details){
|
setDetailComponent(details){
|
||||||
this.loading=true
|
this.loading=true
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import ApiAuthinfo from '../../../api/factory/authinfo.js';
|
|||||||
import BsModal from "../../Bootstrap/Modal.js";
|
import BsModal from "../../Bootstrap/Modal.js";
|
||||||
import FhcOverlay from "../../Overlay/FhcOverlay.js";
|
import FhcOverlay from "../../Overlay/FhcOverlay.js";
|
||||||
import { getDateStyleClass} from "./getDateStyleClass.js";
|
import { getDateStyleClass} from "./getDateStyleClass.js";
|
||||||
|
import { getNow, toDateTime } from "../../../helpers/DateHelpers.js";
|
||||||
import { validateThesisTitle } from './titleValidation.js'
|
import { validateThesisTitle } from './titleValidation.js'
|
||||||
|
|
||||||
export const AbgabetoolStudent = {
|
export const AbgabetoolStudent = {
|
||||||
@@ -171,9 +172,7 @@ export const AbgabetoolStudent = {
|
|||||||
return qgate1positiv && qgate2positiv
|
return qgate1positiv && qgate2positiv
|
||||||
},
|
},
|
||||||
isPastDate(date) {
|
isPastDate(date) {
|
||||||
const deadline = luxon.DateTime.fromISO(date, { zone: 'Europe/Vienna' }).endOf('day');
|
return getNow() > toDateTime(date).endOf("day");
|
||||||
const nowInVienna = luxon.DateTime.now().setZone('Europe/Vienna');
|
|
||||||
return nowInVienna > deadline;
|
|
||||||
},
|
},
|
||||||
setDetailComponent(details){
|
setDetailComponent(details){
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
const zone = 'Europe/Vienna';
|
|
||||||
|
|
||||||
export function getViennaTodayISO() {
|
|
||||||
return luxon.DateTime.now().setZone(zone).toISODate();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatISODate(dateParam) {
|
|
||||||
if (!dateParam) return '';
|
|
||||||
|
|
||||||
const date = luxon.DateTime.fromISO(String(dateParam), { zone });
|
|
||||||
return date.isValid ? date.toFormat('dd.MM.yyyy') : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatDateTime(dateParam) {
|
|
||||||
if (!dateParam) return '';
|
|
||||||
|
|
||||||
const date = luxon.DateTime.fromSQL(dateParam);
|
|
||||||
return date.isValid ? date.toFormat("dd.MM.yyyy HH:mm") : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toViennaDate(dateParam) {
|
|
||||||
if (!dateParam) return null;
|
|
||||||
|
|
||||||
return luxon.DateTime.fromISO(String(dateParam), { zone });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function compareISODateValues(a, b) {
|
|
||||||
if (!a && !b) return 0;
|
|
||||||
if (!a) return 1;
|
|
||||||
if (!b) return -1;
|
|
||||||
|
|
||||||
return String(a).localeCompare(String(b));
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
|
|
||||||
const zone = 'Europe/Vienna';
|
import { getNow, toDateTime } from "../../../helpers/DateHelpers.js";
|
||||||
|
|
||||||
export function getDateStyleClass(termin, notenOptions) {
|
export function getDateStyleClass(termin, notenOptions) {
|
||||||
const today = luxon.DateTime.now().setZone(zone);
|
const today = getNow();
|
||||||
const datum = luxon.DateTime.fromISO(termin.datum, { zone }).endOf('day');
|
const datum = toDateTime(termin.datum)?.endOf('day');
|
||||||
const abgabedatum = termin.abgabedatum ? luxon.DateTime.fromISO(termin.abgabedatum, { zone }) : null;
|
const abgabedatum = toDateTime(termin.abgabedatum);
|
||||||
termin.diffindays = datum.diff(today, 'days').days;
|
termin.diffindays = datum ? datum.diff(today, 'days').days : NaN;
|
||||||
const isLate = abgabedatum && abgabedatum > datum;
|
const isLate = abgabedatum && datum && abgabedatum > datum;
|
||||||
|
|
||||||
// GRADE STATUS
|
// GRADE STATUS
|
||||||
if (termin.note) {
|
if (termin.note) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { numberPadding, formatDate } from "../../../helpers/DateHelpers.js"
|
import { formatDate, formatTime } from "../../../helpers/DateHelpers.js"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
@@ -25,27 +25,14 @@ export default {
|
|||||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/CisVue/Cms/content/${this.event.ort_content_id}`
|
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/CisVue/Cms/content/${this.event.ort_content_id}`
|
||||||
},
|
},
|
||||||
start_time: function () {
|
start_time: function () {
|
||||||
if (!this.event.start) return 'N/A';
|
return this.event.start ? formatTime(this.event.start) : 'N/A';
|
||||||
if (!this.event.start instanceof Date) {
|
|
||||||
return this.event.start;
|
|
||||||
}
|
|
||||||
return numberPadding(this.event.start.getHours()) + ":" + numberPadding(this.event.start.getMinutes());
|
|
||||||
},
|
},
|
||||||
end_time: function () {
|
end_time: function () {
|
||||||
if (!this.event.end) return 'N/A';
|
return this.event.end ? formatTime(this.event.end) : 'N/A';
|
||||||
if (!this.event.end instanceof Date) {
|
|
||||||
return this.event.end;
|
|
||||||
}
|
|
||||||
return numberPadding(this.event.end.getHours()) + ":" + numberPadding(this.event.end.getMinutes());
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
mehtodNumberPadding: function (number) {
|
methodFormatDate: formatDate,
|
||||||
return numberPadding(number);
|
|
||||||
},
|
|
||||||
methodFormatDate: function (d) {
|
|
||||||
return formatDate(d);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
template:/*html*/`
|
template:/*html*/`
|
||||||
<table class="table table-hover mb-4">
|
<table class="table table-hover mb-4">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import FhcCalendar from "../../Calendar/LvPlan.js";
|
import FhcCalendar from "../../Calendar/LvPlan.js";
|
||||||
|
|
||||||
import ApiLvPlan from '../../../api/factory/lvPlan.js';
|
import ApiLvPlan from '../../../api/factory/lvPlan.js';
|
||||||
|
import { getTodayISO } from "../../../helpers/DateHelpers.js";
|
||||||
|
|
||||||
export const DEFAULT_MODE_RAUMINFO_MOBILE = 'List';
|
export const DEFAULT_MODE_RAUMINFO_MOBILE = 'List';
|
||||||
export const DEFAULT_MODE_RAUMINFO_DESKTOP = 'Week';
|
export const DEFAULT_MODE_RAUMINFO_DESKTOP = 'Week';
|
||||||
@@ -17,7 +18,7 @@ export default {
|
|||||||
inject: ["isMobile"],
|
inject: ["isMobile"],
|
||||||
computed: {
|
computed: {
|
||||||
currentDay() {
|
currentDay() {
|
||||||
return this.propsViewData?.focus_date || luxon.DateTime.now().setZone(FHC_JS_DATA_STORAGE_OBJECT.timezone).toISODate();
|
return this.propsViewData?.focus_date || getTodayISO();
|
||||||
},
|
},
|
||||||
currentMode() {
|
currentMode() {
|
||||||
const defaultMode = this.isMobile ? DEFAULT_MODE_RAUMINFO_MOBILE : DEFAULT_MODE_RAUMINFO_DESKTOP;
|
const defaultMode = this.isMobile ? DEFAULT_MODE_RAUMINFO_MOBILE : DEFAULT_MODE_RAUMINFO_DESKTOP;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {CoreFilterCmpt} from "../../../components/filter/Filter.js";
|
import {CoreFilterCmpt} from "../../../components/filter/Filter.js";
|
||||||
import VueDatePicker from '../../vueDatepicker.js.php';
|
import VueDatePicker from '../../vueDatepicker.js.php';
|
||||||
import ApiOrt from '../../../api/factory/ort.js'
|
import ApiOrt from '../../../api/factory/ort.js'
|
||||||
|
import { getNow, getTodayISO } from "../../../helpers/DateHelpers.js";
|
||||||
export const Raumsuche = {
|
export const Raumsuche = {
|
||||||
name: "Raumsuche",
|
name: "Raumsuche",
|
||||||
components: {
|
components: {
|
||||||
@@ -10,6 +11,8 @@ export const Raumsuche = {
|
|||||||
},
|
},
|
||||||
inject: ["isMobile"],
|
inject: ["isMobile"],
|
||||||
data() {
|
data() {
|
||||||
|
const now = getNow();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
phrasenPromise: null,
|
phrasenPromise: null,
|
||||||
phrasenResolved: false,
|
phrasenResolved: false,
|
||||||
@@ -23,14 +26,14 @@ export const Raumsuche = {
|
|||||||
},
|
},
|
||||||
anzahl: 1,
|
anzahl: 1,
|
||||||
selectedType: null,
|
selectedType: null,
|
||||||
datum: new Date(),
|
datum: getTodayISO(),
|
||||||
von: Vue.ref({
|
von: Vue.ref({
|
||||||
hours: new Date().getHours(),
|
hours: now.hour,
|
||||||
minutes: new Date().getMinutes()
|
minutes: now.minute
|
||||||
}),
|
}),
|
||||||
bis: Vue.ref({
|
bis: Vue.ref({
|
||||||
hours: new Date().getHours() + 1,
|
hours: now.plus({ hours: 1 }).hour,
|
||||||
minutes: new Date().getMinutes()
|
minutes: now.minute
|
||||||
}),
|
}),
|
||||||
datepickerTextInputOptions: {
|
datepickerTextInputOptions: {
|
||||||
enterSubmit: true,
|
enterSubmit: true,
|
||||||
@@ -136,7 +139,7 @@ export const Raumsuche = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
loadRooms() {
|
loadRooms() {
|
||||||
this.$api.call(ApiOrt.getRooms(this.datum.toISOString(), this.getTimeString(this.von), this.getTimeString(this.bis), this.selectedType?.raumtyp_kurzbz ?? '', this.anzahl))
|
this.$api.call(ApiOrt.getRooms(this.datum, this.getTimeString(this.von), this.getTimeString(this.bis), this.selectedType?.raumtyp_kurzbz ?? '', this.anzahl))
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if(res?.data?.retval) this.setupData(res.data.retval)
|
if(res?.data?.retval) this.setupData(res.data.retval)
|
||||||
})
|
})
|
||||||
@@ -150,17 +153,6 @@ export const Raumsuche = {
|
|||||||
setRoute(val) {
|
setRoute(val) {
|
||||||
// TODO: router push
|
// TODO: router push
|
||||||
},
|
},
|
||||||
dateFormat(date) {
|
|
||||||
const day = String(date.getDate()).padStart(2, '0');
|
|
||||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
||||||
const year = date.getFullYear();
|
|
||||||
return `${day}.${month}.${year}`
|
|
||||||
},
|
|
||||||
timeFormat(date) {
|
|
||||||
const hours = String(date.getHours()).padStart(2, '0');
|
|
||||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
||||||
return `${hours}:${minutes}`;
|
|
||||||
},
|
|
||||||
async setupMounted() {
|
async setupMounted() {
|
||||||
|
|
||||||
this.tableBuiltPromise = new Promise(this.tableResolve)
|
this.tableBuiltPromise = new Promise(this.tableResolve)
|
||||||
@@ -199,7 +191,8 @@ export const Raumsuche = {
|
|||||||
:dark="isDarkMode"
|
:dark="isDarkMode"
|
||||||
:clearable="false"
|
:clearable="false"
|
||||||
:enable-time-picker="false"
|
:enable-time-picker="false"
|
||||||
:format="dateFormat"
|
format="dd.MM.yyyy"
|
||||||
|
model-type="yyyy-MM-dd"
|
||||||
:text-input="datepickerTextInputOptions"
|
:text-input="datepickerTextInputOptions"
|
||||||
:min-date="new Date()"
|
:min-date="new Date()"
|
||||||
date-picker
|
date-picker
|
||||||
@@ -213,7 +206,7 @@ export const Raumsuche = {
|
|||||||
v-model="von"
|
v-model="von"
|
||||||
:dark="isDarkMode"
|
:dark="isDarkMode"
|
||||||
:clearable="false"
|
:clearable="false"
|
||||||
:format="timeFormat"
|
format="HH:mm"
|
||||||
:text-input="timepickerTextInputOptions"
|
:text-input="timepickerTextInputOptions"
|
||||||
:is-24="true"
|
:is-24="true"
|
||||||
time-picker
|
time-picker
|
||||||
@@ -227,7 +220,7 @@ export const Raumsuche = {
|
|||||||
v-model="bis"
|
v-model="bis"
|
||||||
:dark="isDarkMode"
|
:dark="isDarkMode"
|
||||||
:clearable="false"
|
:clearable="false"
|
||||||
:format="timeFormat"
|
format="HH:mm"
|
||||||
:text-input="timepickerTextInputOptions"
|
:text-input="timepickerTextInputOptions"
|
||||||
:is-24="true"
|
:is-24="true"
|
||||||
time-picker
|
time-picker
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { formatDate, formatDateTime } from "../../helpers/DateHelpers.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
"config",
|
"config",
|
||||||
@@ -30,14 +32,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
formatDateTime: function(dateTime) {
|
formatDateTime,
|
||||||
const dt = new Date(dateTime);
|
getDate: formatDate
|
||||||
return dt.getDate() + '.' + (dt.getMonth()+1) + '.' + dt.getFullYear() + ' | '
|
|
||||||
+ dt.getHours() + ':' + dt.getMinutes();
|
|
||||||
},
|
|
||||||
getDate: function(dateTime){
|
|
||||||
const dt = new Date(dateTime);
|
|
||||||
return dt.getDate() + '.' + (dt.getMonth()+1) + '.' + dt.getFullYear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import AbstractWidget from './Abstract.js';
|
import AbstractWidget from './Abstract.js';
|
||||||
import BsModal from '../Bootstrap/Modal.js';
|
import BsModal from '../Bootstrap/Modal.js';
|
||||||
import { numberPadding } from '../../helpers/DateHelpers.js';
|
import { formatDate, formatTime } from '../../helpers/DateHelpers.js';
|
||||||
import ApiCms from '../../api/factory/cms.js';
|
import ApiCms from '../../api/factory/cms.js';
|
||||||
|
|
||||||
const MAX_LOADED_NEWS = 30;
|
const MAX_LOADED_NEWS = 30;
|
||||||
@@ -84,14 +84,8 @@ export default {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
formatDate: function (dateTime) {
|
formatDate,
|
||||||
const dt = new Date(dateTime);
|
formatTime,
|
||||||
return numberPadding(dt.getDate()) + '.' + numberPadding((dt.getMonth() + 1)) + '.' + dt.getFullYear();
|
|
||||||
},
|
|
||||||
formatTime: function (dateTime) {
|
|
||||||
const dt = new Date(dateTime);
|
|
||||||
return numberPadding(dt.getHours()) + ':' + numberPadding(dt.getMinutes());
|
|
||||||
},
|
|
||||||
isString(value){
|
isString(value){
|
||||||
return Object.prototype.toString.call(value) === '[object String]';
|
return Object.prototype.toString.call(value) === '[object String]';
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,61 +1,69 @@
|
|||||||
|
|
||||||
// HELPER FILE -- that contains multiple functions which create, handle and manipulate js dates
|
// Everything parses and formats with luxon in the server timezone. new Date("2026-09-02")
|
||||||
|
// reads UTC midnight and shows the day before west of Greenwich.
|
||||||
|
|
||||||
// custom Error class for DateHelpers.js misuse
|
|
||||||
class DateHelperError extends Error {
|
function getZone() {
|
||||||
constructor(message) {
|
return globalThis.FHC_JS_DATA_STORAGE_OBJECT?.timezone || 'Europe/Vienna';
|
||||||
super(message);
|
|
||||||
this.name = "DateHelperError";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* adds padding to a number
|
* converts a date value into a luxon DateTime in the server timezone
|
||||||
*
|
*
|
||||||
* @param {number|string} number - the number on which padding should be added.
|
* @param {string|number|Date|Object} value - ISO string, SQL string, milliseconds, Date or luxon DateTime.
|
||||||
* @returns {string} number with padding.
|
* @returns {Object|null} luxon DateTime, or null if the value is empty or unparsable.
|
||||||
*/
|
*/
|
||||||
|
export function toDateTime(value) {
|
||||||
|
if (!value) return null;
|
||||||
|
|
||||||
|
const zone = getZone();
|
||||||
|
let date;
|
||||||
|
|
||||||
|
if (value instanceof luxon.DateTime) date = value.setZone(zone);
|
||||||
|
else if (value instanceof Date) date = luxon.DateTime.fromJSDate(value, { zone });
|
||||||
|
else if (typeof value === 'number') date = luxon.DateTime.fromMillis(value, { zone });
|
||||||
|
// fromISO rejects the space that SQL puts between date and time
|
||||||
|
else if (typeof value === 'string') date = value.includes(' ')
|
||||||
|
? luxon.DateTime.fromSQL(value, { zone })
|
||||||
|
: luxon.DateTime.fromISO(value, { zone });
|
||||||
|
else return null;
|
||||||
|
|
||||||
|
return date.isValid ? date : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// current time in the server timezone
|
||||||
|
export function getNow() {
|
||||||
|
return luxon.DateTime.now().setZone(getZone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// today in the server timezone, as yyyy-MM-dd
|
||||||
|
export function getTodayISO() {
|
||||||
|
return getNow().toISODate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// the three formatters return '' for an empty or unparsable value
|
||||||
|
export function formatDate(value) {
|
||||||
|
return toDateTime(value)?.toFormat('dd.MM.yyyy') ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatTime(value) {
|
||||||
|
return toDateTime(value)?.toFormat('HH:mm') ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatDateTime(value) {
|
||||||
|
return toDateTime(value)?.toFormat('dd.MM.yyyy HH:mm') ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// tabulator sorter for ISO dates, sorts empty values last
|
||||||
|
export function compareISODateValues(a, b) {
|
||||||
|
if (!a && !b) return 0;
|
||||||
|
if (!a) return 1;
|
||||||
|
if (!b) return -1;
|
||||||
|
|
||||||
|
return String(a).localeCompare(String(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
// pads hours and minutes to two digits
|
||||||
export function numberPadding(number) {
|
export function numberPadding(number) {
|
||||||
if(typeof number !== "string" && typeof number !== "number")
|
return String(number).padStart(2, '0');
|
||||||
{
|
|
||||||
throw new TypeError("function numberPadding in file DateHelpers.js is only usable with strings or numbers");
|
|
||||||
}
|
|
||||||
if(number.toString().length > 2)
|
|
||||||
{
|
|
||||||
throw new DateHelperError("The number on which the padding should be added should not be longer than to 2 characters, please refere to the function numberPadding in the helper file DateHelpers.js");
|
|
||||||
}
|
|
||||||
return number.toString().length == 1 ? '0' + number.toString() : number.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* formats date to dd.mm.yyyy
|
|
||||||
*
|
|
||||||
* @param {string|Date} d - the date that should be formatted.
|
|
||||||
* @returns {string} formatted date string.
|
|
||||||
*/
|
|
||||||
export function formatDate(d) {
|
|
||||||
// parameter is of type Date
|
|
||||||
if(d instanceof Date)
|
|
||||||
{
|
|
||||||
if (isNaN(date.valueOf())) {
|
|
||||||
return 'N/A';
|
|
||||||
}
|
|
||||||
// if the date is an invalid string then creating a date from the string will fail and N/A is returned
|
|
||||||
return `${numberPadding(d.getDate())}.${numberPadding(d.getMonth() + 1)}.${d.getFullYear()}`;
|
|
||||||
}
|
|
||||||
// parameter is of type string
|
|
||||||
else if (typeof d === "string")
|
|
||||||
{
|
|
||||||
let date = new Date(d);
|
|
||||||
// if the date is an invalid string then creating a date from the string will fail and N/A is returned
|
|
||||||
if (isNaN(date.valueOf())) {
|
|
||||||
return 'N/A';
|
|
||||||
}
|
|
||||||
return `${numberPadding(date.getDate())}.${numberPadding(date.getMonth() + 1)}.${date.getFullYear()}`;
|
|
||||||
}
|
|
||||||
// parameter is not of type string or Date and an exception is thrown
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new TypeError("The parameter provided for this function is not a string or a Date object, please refere to the function formatDate in the DateHelpers.js file");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user