From a44d0f65b3bb8071a6ceb5e7c587e75555f5757f Mon Sep 17 00:00:00 2001 From: Ivymaster Date: Mon, 4 May 2026 16:28:09 +0200 Subject: [PATCH] Add components and endpoints for room type CRD and room to room type relation CRD --- application/config/routes.php | 2 +- .../controllers/api/frontend/v1/Ort.php | 281 ++++++++------ .../api/frontend/v1/RoomToRoomTypeApi.php | 121 ++++++ .../api/frontend/v1/RoomTypeApi.php | 83 ++++ application/views/room_manager/index.php | 2 +- public/js/api/factory/ort.js | 12 +- public/js/api/factory/roomManager.js | 18 - public/js/api/factory/roomToRoomType.js | 46 +++ public/js/api/factory/roomType.js | 32 ++ .../components/RoomManager/RoomFormModal.js | 82 +++- .../RoomManager/RoomManagerOverview.js | 208 ++++++++--- .../RoomManager/RoomTypeFormModal.js | 353 ++++++++++++++++++ system/dbupdate_3.4.php | 2 +- .../76663_tempus_rekursive_raum_struktur.php | 22 ++ system/phrasesupdate.php | 200 ++++++++++ 15 files changed, 1269 insertions(+), 195 deletions(-) create mode 100644 application/controllers/api/frontend/v1/RoomToRoomTypeApi.php create mode 100644 application/controllers/api/frontend/v1/RoomTypeApi.php delete mode 100644 public/js/api/factory/roomManager.js create mode 100644 public/js/api/factory/roomToRoomType.js create mode 100644 public/js/api/factory/roomType.js create mode 100644 public/js/components/RoomManager/RoomTypeFormModal.js create mode 100644 system/dbupdate_3.4/76663_tempus_rekursive_raum_struktur.php diff --git a/application/config/routes.php b/application/config/routes.php index 3462113f9..11fa7bef4 100644 --- a/application/config/routes.php +++ b/application/config/routes.php @@ -122,7 +122,7 @@ $route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/person/(:num)'] = 'api/f // load routes from extensions, also look for environment-specific configs $subdirs = ['application/config/extensions', 'application/config/' . ENVIRONMENT . '/extensions']; -$route['lehre/RoomManager/.*'] = 'lehre/RoomManager/index'; +$route['RoomManager/.*'] = 'RoomManager/index'; foreach($subdirs as $subdir) { diff --git a/application/controllers/api/frontend/v1/Ort.php b/application/controllers/api/frontend/v1/Ort.php index c8fee5b72..346ac7f8b 100644 --- a/application/controllers/api/frontend/v1/Ort.php +++ b/application/controllers/api/frontend/v1/Ort.php @@ -52,6 +52,7 @@ class Ort extends FHCAPI_Controller $this->loadPhrases([ 'global', 'ui', + 'lehre' ]); } @@ -64,30 +65,49 @@ class Ort extends FHCAPI_Controller $filterData = []; + + $query = "SELECT public.tbl_ort.*, pr.ort_kurzbz as pr_ort_kurzbz, org.bezeichnung as org_bezeichnung + FROM public.tbl_ort + LEFT JOIN public.tbl_ort as pr ON pr.ort_kurzbz = public.tbl_ort.parent_ort_kurzbz + LEFT JOIN public.tbl_organisationseinheit as org ON org.oe_kurzbz = public.tbl_ort.oe_kurzbz"; + + $whereItems = []; + if (isset($filter['locationId']) && $filter['locationId'] !== '') { - $filterData['standort_id'] = $filter['locationId']; + $whereItems[] = 'public.tbl_ort.standort_id = ?'; + $filterData[] = $filter['locationId']; } if (isset($filter['organizationalUnitShortCode']) && $filter['organizationalUnitShortCode'] !== '') { - $filterData['oe_kurzbz'] = $filter['organizationalUnitShortCode']; + $whereItems[] = 'public.tbl_ort.oe_kurzbz = ?'; + $filterData[] = $filter['organizationalUnitShortCode']; } if (isset($filter['buildingComponent']) && $filter['buildingComponent'] !== '') { - $filterData['gebteil'] = $filter['buildingComponent']; + $whereItems[] = 'public.tbl_ort.gebteil = ?'; + $filterData[] = $filter['buildingComponent']; } if (isset($filter['isForTrainingProgram']) && $filter['isForTrainingProgram'] === 'true') { - $filterData['lehre'] = $filter['isForTrainingProgram'] === 'true' ? true : false; + $whereItems[] = 'public.tbl_ort.lehre = ?'; + $filterData[] = $filter['isForTrainingProgram'] === 'true' ? true : false; } if (isset($filter['isReservationNeeded']) && $filter['isReservationNeeded'] === 'true') { - $filterData['reservieren'] = $filter['isReservationNeeded'] === 'true' ? true : false; + $whereItems[] = 'public.tbl_ort.reservieren = ?'; + $filterData[] = $filter['isReservationNeeded'] === 'true' ? true : false; } if (isset($filter['isActive']) && $filter['isActive'] === 'true') { - $filterData['aktiv'] = $filter['isActive'] === 'true' ? true : false; + $whereItems[] = 'public.tbl_ort.aktiv = ?'; + $filterData[] = $filter['isActive'] === 'true' ? true : false; + } + + if (count($whereItems) > 0) { + $query .= ' WHERE ' . implode(' AND ', $whereItems); } - $this->OrtModel->addOrder("ort_kurzbz", "ASC"); + $query .= ' ORDER BY public.tbl_ort.ort_kurzbz ASC'; - $result = $this->OrtModel->loadWhere($filterData); - - $this->terminateWithSuccess($this->getDataOrTerminateWithError($result)); + $result = $this->OrtModel->execReadOnlyQuery($query, $filterData); + + + $this->terminateWithSuccess(getData($result)); } /** @@ -144,8 +164,7 @@ class Ort extends FHCAPI_Controller ) "; $params = array_merge($params, [$datum, $vonStunde, $bisStunde, $datum, $vonStunde, $bisStunde]); -// $this->addMeta('qry', $qry); -// $this->addMeta('params', $params); + $result = $this->OrtModel->execReadOnlyQuery($qry, $params); $this->terminateWithSuccess($result); @@ -234,65 +253,81 @@ class Ort extends FHCAPI_Controller public function createRoom() { - $this->form_validation->set_rules('ort_kurzbz', 'ort_kurzbz', 'required', [ - 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('ui', 'shortCode')]) + $this->form_validation->set_rules('ort_kurzbz', 'kurzbezeichnung', 'required|is_unique[tbl_ort.ort_kurzbz]', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'kurzbz')]) + ]); + $this->form_validation->set_rules('content_id', 'content_id', 'number', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'content_id')]) ]); - if($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array()); + $parent_ort_kurzbz = $this->input->post('parent_ort_kurzbz'); + if ($parent_ort_kurzbz) { + $this->load->model('ressource/Ort_model', 'ParentRoomModel'); + $parentRoom = $this->ParentRoomModel->load($parent_ort_kurzbz); + if (isError($parentRoom) || !hasData($parentRoom)) { + $this->terminateWithError("Parent room with shortcode $parent_ort_kurzbz does not exist", self::ERROR_TYPE_GENERAL); + } + } + + $oe_kurzbz = $this->input->post('oe_kurzbz'); + if ($oe_kurzbz) { + $this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel'); + $orgUnit = $this->OrganisationseinheitModel->load($oe_kurzbz); + if (isError($orgUnit) || !hasData($orgUnit)) { + $this->terminateWithError("Organizational unit with shortcode $oe_kurzbz does not exist", self::ERROR_TYPE_GENERAL); + } + } + + $standort_id = $this->input->post('standort_id'); + if ($standort_id) { + $this->load->model('organisation/Standort_model', 'StandortModel'); + $location = $this->StandortModel->load($standort_id); + if (isError($location) || !hasData($location)) { + $this->terminateWithError("Location with id $standort_id does not exist", self::ERROR_TYPE_GENERAL); + } + } + + $content_id = $this->input->post('content_id'); + if ($content_id) { + $this->load->model('content/Content_model', 'ContentModel'); + $content = $this->ContentModel->load($content_id); + if (isError($content) || !hasData($content)) { + $this->terminateWithError("Content with id $content_id does not exist", self::ERROR_TYPE_GENERAL); + } + } + $this->db->trans_start(); - $result = $this->OrtModel->db->query("INSERT INTO public.tbl_ort - ( - oe_kurzbz, - content_id, - standort_id, - ort_kurzbz, - bezeichnung, - planbezeichnung, - aktiv, - lehre, - reservieren, - max_person, - stockwerk, - lageplan, - dislozierung, - kosten, - ausstattung, - telefonklappe, - m2, - gebteil, - arbeitsplaetze, - insertamum, - insertvon, - updateamum, - updatevon - ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [ - $this->input->post('oe_kurzbz'), - $this->input->post('contentId'), - $this->input->post('standort_id'), - $this->input->post('ort_kurzbz'), - $this->input->post('bezeichnung'), - $this->input->post('planbezeichnung'), - $this->input->post('aktiv') ? true : false, - $this->input->post('lehre') ? true : false, - $this->input->post('reservieren') ? true : false, - $this->input->post('max_person'), - $this->input->post('stockwerk'), - $this->input->post('lageplan'), - $this->input->post('dislozierung'), - $this->input->post('kosten'), - $this->input->post('ausstattung'), - $this->input->post('telefonklappe'), - $this->input->post('m2'), - $this->input->post('gebteil'), - $this->input->post('arbeitsplatze'), - date('c'), - getAuthUid(), - date('c'), - getAuthUid() - ]); + $data = [ + "parent_ort_kurzbz" => $this->input->post('parent_ort_kurzbz'), + "oe_kurzbz" => $this->input->post('oe_kurzbz'), + "content_id" => !empty($this->input->post('content_id')) ? $this->input->post('content_id') : null, + "standort_id" => $this->input->post('standort_id'), + "ort_kurzbz" => $this->input->post('ort_kurzbz'), + "bezeichnung" => $this->input->post('bezeichnung'), + "planbezeichnung" => $this->input->post('planbezeichnung'), + "aktiv" => $this->input->post('aktiv') ? true : false, + "lehre" => $this->input->post('lehre') ? true : false, + "reservieren" => $this->input->post('reservieren') ? true : false, + "max_person" => $this->input->post('max_person'), + "stockwerk" => $this->input->post('stockwerk'), + "lageplan" => $this->input->post('lageplan'), + "dislozierung" => $this->input->post('dislozierung'), + "kosten" => $this->input->post('kosten'), + "ausstattung" => $this->input->post('ausstattung'), + "telefonklappe" => $this->input->post('telefonklappe'), + "m2" => $this->input->post('m2'), + "gebteil" => $this->input->post('gebteil'), + "arbeitsplaetze" => $this->input->post('arbeitsplatze'), + 'insertamum' => date('c'), + 'insertvon' => getAuthUid(), + 'updateamum' => date('c'), + 'updatevon' => getAuthUid() + ]; + + $this->OrtModel->db->set($data); + $result = $this->OrtModel->db->insert($this->OrtModel->getDbTable()); $this->db->trans_complete(); @@ -306,52 +341,78 @@ class Ort extends FHCAPI_Controller $this->terminateWithError("missing ort_kurzbz parameter", self::ERROR_TYPE_GENERAL); } + $parent_ort_kurzbz = $this->input->post('parent_ort_kurzbz'); + if ($parent_ort_kurzbz) { + $this->load->model('ressource/Ort_model', 'ParentRoomModel'); + $parentRoom = $this->ParentRoomModel->load($parent_ort_kurzbz); + if (isError($parentRoom) || !hasData($parentRoom)) { + $this->terminateWithError("Parent room with shortcode $parent_ort_kurzbz does not exist", self::ERROR_TYPE_GENERAL); + } + } + + $oe_kurzbz = $this->input->post('oe_kurzbz'); + if ($oe_kurzbz) { + $this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel'); + $orgUnit = $this->OrganisationseinheitModel->load($oe_kurzbz); + if (isError($orgUnit) || !hasData($orgUnit)) { + $this->terminateWithError("Organizational unit with shortcode $oe_kurzbz does not exist", self::ERROR_TYPE_GENERAL); + } + } + + $standort_id = $this->input->post('standort_id'); + if ($standort_id) { + $this->load->model('organisation/Standort_model', 'StandortModel'); + $location = $this->StandortModel->load($standort_id); + if (isError($location) || !hasData($location)) { + $this->terminateWithError("Location with id $standort_id does not exist", self::ERROR_TYPE_GENERAL); + } + } + + $content_id = $this->input->post('content_id'); + if ($content_id) { + $this->load->model('content/Content_model', 'ContentModel'); + $content = $this->ContentModel->load($content_id); + if (isError($content) || !hasData($content)) { + $this->terminateWithError("Content with id $content_id does not exist", self::ERROR_TYPE_GENERAL); + } + } + $this->db->trans_start(); - $result = $this->OrtModel->db->query("UPDATE public.tbl_ort SET - oe_kurzbz = ?, - content_id = ?, - standort_id = ?, - bezeichnung = ?, - planbezeichnung = ?, - aktiv = ?, - lehre = ?, - reservieren = ?, - max_person = ?, - stockwerk = ?, - lageplan = ?, - dislozierung = ?, - kosten = ?, - ausstattung = ?, - telefonklappe = ?, - m2 = ?, - gebteil = ?, - arbeitsplaetze = ?, - updateamum = ?, - updatevon = ? - WHERE ort_kurzbz = ?", [ - $this->input->post('oe_kurzbz'), - $this->input->post('contentId'), - $this->input->post('standort_id'), - $this->input->post('bezeichnung'), - $this->input->post('planbezeichnung'), - $this->input->post('aktiv') ? true : false, - $this->input->post('lehre') ? true : false, - $this->input->post('reservieren') ? true : false, - $this->input->post('max_person'), - $this->input->post('stockwerk'), - $this->input->post('lageplan'), - $this->input->post('dislozierung'), - $this->input->post('kosten'), - $this->input->post('ausstattung'), - $this->input->post('telefonklappe'), - $this->input->post('m2'), - $this->input->post('gebteil'), - $this->input->post('arbeitsplatze'), - date('c'), - getAuthUid(), - $ort_kurzbz - ]); + $fields = [ + "parent_ort_kurzbz", + "oe_kurzbz", + "content_id", + "standort_id", + "bezeichnung", + "planbezeichnung", + "aktiv", + "lehre", + "reservieren", + "max_person", + "stockwerk", + "lageplan", + "dislozierung", + "kosten", + "ausstattung", + "telefonklappe", + "m2", + "gebteil", + "arbeitsplaetze" + ]; + + foreach ($fields as $field) { + if (array_key_exists($field, $this->input->post())) { + $data[$field] = $this->input->post($field); + } + } + + $data['updateamum'] = date('c'); + $data['updatevon'] = getAuthUid(); + + $this->OrtModel->db->set($data); + $this->OrtModel->db->where('ort_kurzbz', $ort_kurzbz); + $result = $this->OrtModel->db->update($this->OrtModel->getDbTable()); $this->db->trans_complete(); diff --git a/application/controllers/api/frontend/v1/RoomToRoomTypeApi.php b/application/controllers/api/frontend/v1/RoomToRoomTypeApi.php new file mode 100644 index 000000000..0cf4afcb9 --- /dev/null +++ b/application/controllers/api/frontend/v1/RoomToRoomTypeApi.php @@ -0,0 +1,121 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller operates between (interface) the JS (GUI) and the SearchBarLib (back-end) + * Provides data to the ajax get calls about the searchbar component + * This controller works with JSON calls on the HTTP GET and the output is always JSON + */ +class RoomToRoomTypeApi extends FHCAPI_Controller +{ + + /** + * Object initialization + */ + public function __construct() + { + // NOTE(chris): additional permission checks will be done in SearchBarLib + parent::__construct([ + 'getRoomToRoomTypeRelationsByRoomShortCode' => self::PERM_LOGGED, + 'createRoomToRoomTypeRelation' => self::PERM_LOGGED, + 'deleteRoomToRoomTypeRelation' => self::PERM_LOGGED, + ]); + + $this->load->library('form_validation'); + + $this->load->model('ressource/Ortraumtyp_model', 'OrtRoomTypeModel'); + + $this->loadPhrases([ + 'global', + 'ui', + 'lehre' + ]); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + public function getRoomToRoomTypeRelationsByRoomShortCode($roomShortCode) { + $this->OrtRoomTypeModel->db->select('public.tbl_ortraumtyp.*, public.tbl_raumtyp.beschreibung as raumtyp_beschreibung'); + $this->OrtRoomTypeModel->db->join('public.tbl_raumtyp', 'public.tbl_raumtyp.raumtyp_kurzbz = public.tbl_ortraumtyp.raumtyp_kurzbz', 'left'); + $this->OrtRoomTypeModel->db->order_by('hierarchie', 'ASC'); + $result = $this->OrtRoomTypeModel->loadWhere(['ort_kurzbz' => $roomShortCode]); + + return $this->terminateWithSuccess($this->getDataOrTerminateWithError($result)); + } + + public function createRoomToRoomTypeRelation() { + $this->form_validation->set_rules('roomShortCode', 'roomShortCode', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'kurzbz')]) + ]); + $this->form_validation->set_rules('roomTypeShortCode', 'roomTypeShortCode', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'kurzbz')]) + ]); + $this->form_validation->set_rules('hierarchy', 'hierarchy', 'required|integer', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('ui', 'hierarchy')]), + 'integer' => $this->p->t('ui', 'error_fieldInteger', ['field' => $this->p->t('ui', 'hierarchy')]) + ]); + + if($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $existingRelationResponse = $this->OrtRoomTypeModel->loadWhere([ + 'ort_kurzbz' => $this->input->post('roomShortCode'), + 'hierarchie' => $this->input->post('hierarchy'), + ]); + if (hasData($existingRelationResponse)) { + $this->terminateWithError($this->p->t('ui', 'error_roomToRoomTypeRelationAlreadyExists'), self::ERROR_TYPE_GENERAL); + } + + $data = [ + 'ort_kurzbz' => $this->input->post('roomShortCode'), + 'raumtyp_kurzbz' => $this->input->post('roomTypeShortCode'), + 'hierarchie' => $this->input->post('hierarchy'), + ]; + + $this->OrtRoomTypeModel->db->set($data); + $result = $this->OrtRoomTypeModel->db->insert($this->OrtRoomTypeModel->getDbTable()); + + if ($result === false) { + return $this->terminateWithError($this->OrtRoomTypeModel->getLastError()); + } + + return $this->terminateWithSuccess(['message' => 'Room to Room Type relation created successfully.']); + } + + public function deleteRoomToRoomTypeRelation() { + $this->form_validation->set_rules('roomShortCode', 'roomShortCode', 'required'); + $this->form_validation->set_rules('roomTypeShortCode', 'roomTypeShortCode', 'required'); + + if ($this->form_validation->run() === false) { + return $this->terminateWithError(validation_errors()); + } + + $result = $this->OrtRoomTypeModel->db->delete($this->OrtRoomTypeModel->getDbTable(), [ + 'ort_kurzbz' => $this->input->post('roomShortCode'), + 'raumtyp_kurzbz' => $this->input->post('roomTypeShortCode'), + ]); + + if ($result === false) { + return $this->terminateWithError($this->OrtRoomTypeModel->getLastError()); + } + + return $this->terminateWithSuccess(['message' => 'Room to Room Type relation deleted successfully.']); + } +} + diff --git a/application/controllers/api/frontend/v1/RoomTypeApi.php b/application/controllers/api/frontend/v1/RoomTypeApi.php new file mode 100644 index 000000000..d1dcda770 --- /dev/null +++ b/application/controllers/api/frontend/v1/RoomTypeApi.php @@ -0,0 +1,83 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller operates between (interface) the JS (GUI) and the SearchBarLib (back-end) + * Provides data to the ajax get calls about the searchbar component + * This controller works with JSON calls on the HTTP GET and the output is always JSON + */ +class RoomTypeApi extends FHCAPI_Controller +{ + + /** + * Object initialization + */ + public function __construct() + { + parent::__construct([ + 'getAllRoomTypes' => self::PERM_LOGGED, + 'createRoomType' => self::PERM_LOGGED, + ]); + + $this->load->library('form_validation'); + + $this->load->model('ressource/Raumtyp_model', 'RoomTypeModel'); + + $this->loadPhrases([ + 'global', + 'ui', + 'lehre' + ]); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + public function getAllRoomTypes() { + $this->RoomTypeModel->addOrder('raumtyp_kurzbz', 'ASC'); + $result = $this->RoomTypeModel->load(); + + return $this->terminateWithSuccess($this->getDataOrTerminateWithError($result)); + } + + public function createRoomType() { + $this->form_validation->set_rules('kurzbezeichnung', 'kurzbezeichnung', 'required|max_length[255]|is_unique[tbl_raumtyp.raumtyp_kurzbz]', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => $this->p->t('lehre', 'kurzbz')]), + 'is_unique' => $this->p->t('ui', 'error_fieldUnique', ['field' => $this->p->t('lehre', 'kurzbz')]), + ]); + $this->form_validation->set_rules('beschreibung', 'beschreibung', 'max_length[255]'); + + if($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $data = [ + 'raumtyp_kurzbz' => $this->input->post('kurzbezeichnung'), + 'beschreibung' => $this->input->post('beschreibung'), + ]; + + $this->RoomTypeModel->db->set($data); + $result = $this->RoomTypeModel->db->insert($this->RoomTypeModel->getDbTable()); + + if ($result === false) { + return $this->terminateWithError($this->RoomTypeModel->getLastError()); + } + + return $this->terminateWithSuccess(); + } +} + diff --git a/application/views/room_manager/index.php b/application/views/room_manager/index.php index a355fa857..0f7c4122e 100644 --- a/application/views/room_manager/index.php +++ b/application/views/room_manager/index.php @@ -1,6 +1,6 @@ 'Raumverwaltung', + 'title' => ucfirst($this->p->t('ui', 'roomManagerPageTitle')), 'vue3' => true, 'axios027' => true, 'bootstrap5' => true, diff --git a/public/js/api/factory/ort.js b/public/js/api/factory/ort.js index ee6a477ac..5b20ce3bc 100644 --- a/public/js/api/factory/ort.js +++ b/public/js/api/factory/ort.js @@ -21,12 +21,12 @@ export default { method: 'get', url: 'api/frontend/v1/Ort/getAllRooms', params: { - "filter[organizationalUnitShortCode]" : params.organizationalUnitShortCode, - "filter[locationId]" : params.locationId, - "filter[buildingComponent]" : params.buildingComponent, - "filter[isForTrainingProgram]" : params.isForTrainingProgram, - "filter[isReservationNeeded]" : params.isReservationNeeded, - "filter[isActive]" : params.isActive, + "filter[organizationalUnitShortCode]" : params?.organizationalUnitShortCode, + "filter[locationId]" : params?.locationId, + "filter[buildingComponent]" : params?.buildingComponent, + "filter[isForTrainingProgram]" : params?.isForTrainingProgram, + "filter[isReservationNeeded]" : params?.isReservationNeeded, + "filter[isActive]" : params?.isActive, } } }, diff --git a/public/js/api/factory/roomManager.js b/public/js/api/factory/roomManager.js deleted file mode 100644 index c538e7596..000000000 --- a/public/js/api/factory/roomManager.js +++ /dev/null @@ -1,18 +0,0 @@ - -export default { - getAllRooms(params) { - console.log("API Call with params: ", params); - return { - method: 'get', - url: 'api/frontend/v1/Ort/getAllRooms', - params: { - "filter[organizationalUnitShortCode]" : params.organizationalUnitShortCode, - "filter[locationId]" : params.locationId, - "filter[buildingComponent]" : params.buildingComponent, - "filter[isForTrainingProgram]" : params.isForTrainingProgram, - "filter[isReservationNeeded]" : params.isReservationNeeded, - "filter[isActive]" : params.isActive, - } - } - }, -}; \ No newline at end of file diff --git a/public/js/api/factory/roomToRoomType.js b/public/js/api/factory/roomToRoomType.js new file mode 100644 index 000000000..e62e4426f --- /dev/null +++ b/public/js/api/factory/roomToRoomType.js @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2025 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 { + getRoomToRoomTypeRelationsByRoomShortCode(roomShortCode) { + return { + method: 'get', + url: `api/frontend/v1/RoomToRoomTypeApi/getRoomToRoomTypeRelationsByRoomShortCode/${roomShortCode}`, + } + }, + createRoomToRoomTypeRelation(roomShortCode, roomTypeShortCode, hierarchy) { + return { + method: 'post', + url: `api/frontend/v1/RoomToRoomTypeApi/createRoomToRoomTypeRelation`, + params: { + roomShortCode, + roomTypeShortCode, + hierarchy + }, + } + }, + deleteRoomToRoomTypeRelation(roomShortCode, roomTypeShortCode) { + return { + method: 'post', + url: `api/frontend/v1/RoomToRoomTypeApi/deleteRoomToRoomTypeRelation`, + params: { + roomShortCode, + roomTypeShortCode + }, + } + } +}; \ No newline at end of file diff --git a/public/js/api/factory/roomType.js b/public/js/api/factory/roomType.js new file mode 100644 index 000000000..437c5813e --- /dev/null +++ b/public/js/api/factory/roomType.js @@ -0,0 +1,32 @@ +/** + * Copyright (C) 2025 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 { + getAllRoomTypes() { + return { + method: 'get', + url: 'api/frontend/v1/RoomTypeApi/getAllRoomTypes', + } + }, + createRoomType(roomTypeData) { + return { + method: 'post', + url: 'api/frontend/v1/RoomTypeApi/createRoomType', + params: roomTypeData, + } + }, +}; \ No newline at end of file diff --git a/public/js/components/RoomManager/RoomFormModal.js b/public/js/components/RoomManager/RoomFormModal.js index a8e83100c..4040ca010 100644 --- a/public/js/components/RoomManager/RoomFormModal.js +++ b/public/js/components/RoomManager/RoomFormModal.js @@ -46,6 +46,8 @@ export default { organizationalUnits: [], filteredOrganizationalUnits: [], locations: [], + rooms: [], + filteredRooms: [], editedRoom: null, roomFormData: { aktiv: true, @@ -61,6 +63,14 @@ export default { }; }); }, + dropdownParsedRooms() { + return this.rooms.map((room) => { + return { + label: `${room.ort_kurzbz} - ${room.bezeichnung}`, + value: room.ort_kurzbz, + }; + }); + }, }, methods: { filterOrganizationalUnits(event) { @@ -83,6 +93,26 @@ export default { }), )); }, + filterRooms(event) { + let defaultItem = { + label: "----------", + value: null, + }; + + const query = event.query.toLowerCase(); + if (!query) { + return (this.filteredRooms = [ + defaultItem, + ...this.dropdownParsedRooms, + ]); + } + + return (this.filteredRooms = [defaultItem] + .concat(this.dropdownParsedRooms) + .filter((room) => { + return room.label?.toLowerCase().includes(query); + })); + }, createRoom() { return this.$refs.roomForm .call(ApiRoom.createRoom(this.getApiCallParsedRoomFormData())) @@ -108,19 +138,30 @@ export default { return; } - this.isEditInProgress = true; + let orgUnitData = null; let orgUnit = this.organizationalUnits.find( (unit) => unit.oe_kurzbz === this.editedRoom.oe_kurzbz, ); + if (orgUnit) { + orgUnitData = { + label: `${orgUnit.bezeichnung} (${orgUnit.organisationseinheittyp_kurzbz})`, + value: orgUnit.oe_kurzbz, + }; + } - let orgUnitData = { - label: `${orgUnit.bezeichnung} (${orgUnit.organisationseinheittyp_kurzbz})`, - value: orgUnit.oe_kurzbz, + + let parentRoom = this.rooms.find( + (room) => room.ort_kurzbz === this.editedRoom.parent_ort_kurzbz, + ); + let parentRoomData = { + label: parentRoom?.bezeichnung || "", + value: parentRoom?.ort_kurzbz || null, }; this.roomFormData = { + parentRoom: parentRoomData, locationId: this.editedRoom.standort_id, organizationalUnit: orgUnitData, contentId: this.editedRoom.content_id, @@ -161,6 +202,7 @@ export default { }, getApiCallParsedRoomFormData() { return { + parent_ort_kurzbz: this.roomFormData.parentRoom?.value, standort_id: this.roomFormData.locationId, oe_kurzbz: this.roomFormData.organizationalUnit?.value, content_id: this.roomFormData.contentId, @@ -188,6 +230,7 @@ export default { this.resetRoomForm(); }, resetRoomForm() { + this.$refs.roomForm.clearValidation(); this.isEditInProgress = false; this.editedRoom = null; this.roomFormData = { @@ -221,6 +264,18 @@ export default { getAllOrganizationalUnitsResponse.meta.message, ); } + + let getRoomsResponse = await this.$api.call( + ApiRoom.getAllRooms(), + ); + if (getRoomsResponse.meta.status === "success") { + this.rooms = getRoomsResponse.data; + } else { + console.error( + "Error fetching rooms:", + getRoomsResponse.meta.message, + ); + } }, template: /* html */ ` @@ -230,6 +285,21 @@ export default {