diff --git a/application/controllers/api/frontend/v1/dropdowns/Dropdown.php b/application/controllers/api/frontend/v1/dropdowns/Dropdown.php new file mode 100644 index 000000000..839d30fd7 --- /dev/null +++ b/application/controllers/api/frontend/v1/dropdowns/Dropdown.php @@ -0,0 +1,51 @@ +. + */ + +if (!defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Dropdown extends FHCAPI_Controller +{ + /** + * Calls the parent's constructor and prepares libraries and phrases + */ + public function __construct() + { + parent::__construct([ + 'getNations' => self::PERM_LOGGED + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + } + + public function getNations($searchString=null) + { + $this->load->model('codex/nation_model', 'NationModel'); + + $result = $this->NationModel->searchNations($searchString); + if (isError($result)) { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess($result ?: []); + } +} \ No newline at end of file diff --git a/application/controllers/api/frontend/v1/stv/Address.php b/application/controllers/api/frontend/v1/stv/Address.php index d14111e99..fcac421b8 100644 --- a/application/controllers/api/frontend/v1/stv/Address.php +++ b/application/controllers/api/frontend/v1/stv/Address.php @@ -42,11 +42,15 @@ class Address extends FHCAPI_Controller { $this->load->model('codex/Nation_model', 'NationModel'); - $this->NationModel->addOrder('kurztext'); + //show at first entries staatenlos and Stbg. ungeklaert + $this->db->order_by("kontinent IS NULL DESC, kurztext ASC", '', FALSE); + $this->NationModel->addSelect("langtext as label"); + $this->NationModel->addSelect('kurztext'); + $this->NationModel->addSelect('nation_code'); $result = $this->NationModel->load(); $data = $this->getDataOrTerminateWithError($result); - + $this->terminateWithSuccess($data); } diff --git a/application/models/codex/Nation_model.php b/application/models/codex/Nation_model.php index ee38c9051..6c7e333d0 100644 --- a/application/models/codex/Nation_model.php +++ b/application/models/codex/Nation_model.php @@ -11,4 +11,39 @@ class Nation_model extends DB_Model $this->dbTable = 'bis.tbl_nation'; $this->pk = 'nation_code'; } + + public function searchNations($filter=null) + { + $params = []; + + if ($filter) + { + if (preg_match('/%[0-9A-Fa-f]{2}/', $filter)) { + $filter = urldecode($filter); + } + $filter = mb_strtolower($filter, 'UTF-8'); //for umlaute + } + + $qry = " + SELECT + n.nation_code, n.langtext as label, n.kurztext, n.sperre + FROM + bis.tbl_nation n"; + + if ($filter) + { + $escapedFilter = $this->db->escape('%' . $filter . '%'); + + $qry .= " + WHERE + n.kurztext ILIKE $escapedFilter + OR n.engltext ILIKE $escapedFilter + OR n.nation_code ILIKE $escapedFilter + "; + } + + $qry .= " ORDER BY n.kontinent IS NULL DESC, n.kurztext ASC"; + + return $this->execQuery($qry, $params); + } } diff --git a/application/views/Studentenverwaltung.php b/application/views/Studentenverwaltung.php index 5b6138ff8..71c83c76b 100644 --- a/application/views/Studentenverwaltung.php +++ b/application/views/Studentenverwaltung.php @@ -21,7 +21,8 @@ 'public/css/components/primevue.css', 'public/css/Studentenverwaltung.css', 'public/css/components/function.css', - 'public/css/components/Detailheader.css' + 'public/css/components/Detailheader.css', + 'public/css/components/dropdown.css' ], 'customJSs' => [ 'vendor/vuejs/vuedatepicker_js/vue-datepicker.iife.js', diff --git a/public/css/components/dropdown.css b/public/css/components/dropdown.css new file mode 100644 index 000000000..20d0b3caa --- /dev/null +++ b/public/css/components/dropdown.css @@ -0,0 +1,3 @@ +.item-sperre { + text-decoration: line-through; +} \ No newline at end of file diff --git a/public/js/api/dropdowns/dropdown.js b/public/js/api/dropdowns/dropdown.js new file mode 100644 index 000000000..03efcf86a --- /dev/null +++ b/public/js/api/dropdowns/dropdown.js @@ -0,0 +1,25 @@ +/** + * Copyright (C) 2026 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +export default { + getNations(searchString) { + return { + method: 'get', + url: 'api/frontend/v1/dropdowns/dropdown/getNations/' + searchString + }; + } +}; diff --git a/public/js/components/Dropdowns/NationsDropdown.js b/public/js/components/Dropdowns/NationsDropdown.js new file mode 100644 index 000000000..a69879c24 --- /dev/null +++ b/public/js/components/Dropdowns/NationsDropdown.js @@ -0,0 +1,109 @@ +import CoreForm from '../Form/Form.js'; +import FormInput from '../Form/Input.js'; +import ApiDropdowns from '../../api/dropdowns/dropdown.js'; + +export default { + name: "NationsDropdown", + components: { + CoreForm, + FormInput + }, + inject: { + lists: { + from: 'lists' + }, + }, + props: { + nation: { + type: String, + required: true + }, + containerClass: { + type: String, + required: false + }, + labelDropdown: { + type: String, + required: false + }, + nullLabel: { + type: String, + required: false, + default: '' + }, + }, + data(){ + return { + filteredNations: [], + selectedNation: null, + abortController: { + nations: null + }, + }; + }, + watch: { + nation: { + immediate: true, + handler(newVal) { + if (newVal) { + this.updateNation(newVal); + } + } + }, + selectedNation(newVal) { + //emit + this.$emit('updateNation', { + nation_code: newVal?.nation_code + }); + } + }, + methods: { + filterNations(event){ + //use search function instead of filteringList to get also params of engltext and nation_code + if (this.abortController.nations) { + this.abortController.nations.abort(); + } + this.abortController.nations = new AbortController(); + + return this.$api + .call(ApiDropdowns.getNations(event.query)) + .then(result => { + this.filteredNations = result.data.retval; + }); + }, + updateNation(nation) { + const detailsNation = this.lists.nations.find( + item => item.nation_code == nation + ); + + //create new object to avoid erros because of same instance if included more than once + this.selectedNation = detailsNation + ? { ...detailsNation } + : { nation_code: nation, label: this.nullLabel }; + }, + }, + template: ` +
+ + + +
` +}; diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Details.js index 0b5eec44d..23c94c540 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Details.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Details.js @@ -3,17 +3,18 @@ import FormInput from '../../../Form/Input.js'; import FormUploadImage from '../../../Form/Upload/Image.js'; import CoreUdf from '../../../Udf/Udf.js'; +import NationsDropdown from '../../../Dropdowns/NationsDropdown.js'; import ApiStvDetails from '../../../../api/factory/stv/details.js'; - export default { name: "TabDetails", components: { CoreForm, FormInput, FormUploadImage, - CoreUdf + CoreUdf, + NationsDropdown }, inject: { showBpk: { @@ -54,11 +55,14 @@ export default { default: {} } }, + emits: [ + 'updateNation' + ], data() { return { original: null, data: null, - changed: {} + changed: {}, } }, computed: { @@ -79,7 +83,7 @@ export default { "v": this.$p.t('person', 'verheiratet'), "w": this.$p.t('person', 'verwitwet'), }; - } + }, }, watch: { modelValue(n) { @@ -100,7 +104,7 @@ export default { this.changed = res; }, deep: true - } + }, }, methods: { updateStudent(n) { @@ -168,6 +172,12 @@ export default { const bodyEncoded = encodeURIComponent(bodyWithNewLines); window.location.href = "mailto:" + this.modelValue.mail_intern + "?subject=" + subjectEncoded + "&body=" + bodyEncoded; + }, + handleChangeNation({nation_code}){ + this.data.geburtsnation = nation_code; + }, + handleChangeStbg({nation_code}){ + this.data.staatsbuergerschaft = nation_code; } }, created() { @@ -325,28 +335,26 @@ export default { maxlength="128" > - - - - - + + - - - + > +
diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Address.js b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Address.js index 7e73b13d2..016b9c600 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Address.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Address.js @@ -4,6 +4,7 @@ import FhcFormValidation from '../../../../Form/Validation.js'; import BsModal from "../../../../Bootstrap/Modal.js"; import FormForm from '../../../../Form/Form.js'; import FormInput from '../../../../Form/Input.js'; +import NationsDropdown from '../../../../Dropdowns/NationsDropdown.js'; import ApiStvAddress from '../../../../../api/factory/stv/kontakt/address.js'; @@ -15,11 +16,15 @@ export default{ FhcFormValidation, BsModal, FormForm, - FormInput + FormInput, + NationsDropdown }, props: { uid: Number }, + emits: [ + 'updateNation' + ], data() { return { addressData: { @@ -231,7 +236,6 @@ export default{ // delete this.addressData.plz; this.loadPlaces(this.addressData.address.plz); this.$refs.adressModal.show(); - } }); }, @@ -338,6 +342,9 @@ export default{ this.statusNew = true; }, + handleChangeNation({nation_code}){ + this.addressData.nation = nation_code; + }, }, created() { this.$api @@ -397,182 +404,174 @@ export default{ v-model="addressData.strasse" > -
+ -
- - - -
- -
- - -
+
+ + +
-
- - - - - + + +
+ +
+ - -
- -
- - - - - {{$p.t('ui', 'bittePlzWaehlen')}} + + + + +
+ +
+ - -
- -
-
+ > + + + + v-else + type="text" + :label="$p.t('person/ort')" + name="ort" + v-model="addressData.ort" + >
-
-
-
- - +
+
+ + +
-
-
- - -
- -
-
- - +
+
+ + +
-
-
- - -
- -
- -
- -
- - -
- -
- + - -
+ +
+
+
+ + +
+
+ +
+ + +
+ +
+ +
+ +
+ + +
+ +
+ + +