diff --git a/application/controllers/api/frontend/v1/messages/Messages.php b/application/controllers/api/frontend/v1/messages/Messages.php index f81e85e9a..adf1d52e9 100644 --- a/application/controllers/api/frontend/v1/messages/Messages.php +++ b/application/controllers/api/frontend/v1/messages/Messages.php @@ -36,7 +36,7 @@ class Messages extends FHCAPI_Controller $this->terminateWithError("logic for type_id " . $type_id . " not defined yet", self::ERROR_TYPE_GENERAL); } - $result = $this->MessageModel->getMessagesOfPerson($id); + $result = $this->MessageModel->getMessagesForTable($id); $data = $this->getDataOrTerminateWithError($result); diff --git a/application/models/system/Message_model.php b/application/models/system/Message_model.php index 6288f54f3..1b201fc1b 100644 --- a/application/models/system/Message_model.php +++ b/application/models/system/Message_model.php @@ -109,10 +109,7 @@ class Message_model extends DB_Model re.vornamen AS revornamen, s.status, s.statusinfo, - s.insertamum AS statusamum, - CONCAT(se.titelpre, ' ', se.vorname, ' ', se.nachname, ' ', se.titelpost) as sender, - CONCAT(re.titelpre, ' ', re.vorname, ' ', re.nachname, ' ', re.titelpost ) as recipient, - TO_CHAR(s.insertamum::timestamp, 'DD.MM.YYYY HH24:MI') AS format_insertamum + s.insertamum AS statusamum FROM public.tbl_msg_message m JOIN public.tbl_msg_recipient r ON m.message_id = r.message_id JOIN public.tbl_person se ON (m.person_id = se.person_id) @@ -233,4 +230,56 @@ class Message_model extends DB_Model return $this->execQuery($query, $params); } + + /** + * Gets messages for a person for tableMessages. + * @param $person_id + * @param null $status message status. by default, latest status is returned + * @return array|null + */ + public function getMessagesForTable($person_id, $status = null) + { + $sql = " + SELECT + m.message_id AS message_id, + m.subject AS subject, + m.body AS body, + m.insertamum AS insertamum, + m.relationmessage_id AS relationmessage_id, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = m.person_id) as sender, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = r.person_id) as recipient, + m.person_id as sender_id, + r.person_id as recipient_id, + MAX(ss.status) as status, + MAX(ss.insertamum) as statusdatum + FROM public.tbl_msg_message m + JOIN public.tbl_msg_recipient r USING(message_id) + JOIN public.tbl_msg_status ss ON(r.message_id = ss.message_id AND ss.person_id = r.person_id) + WHERE m.person_id = ? + GROUP BY m.message_id, m.subject, m.body, m.insertamum, m.relationmessage_id, sender, recipient, sender_id, recipient_id + UNION ALL + SELECT + m.message_id AS message_id, + m.subject AS subject, + m.body AS body, + m.insertamum AS insertamum, + m.relationmessage_id AS relationmessage_id, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = m.person_id) as sender, + (SELECT COALESCE(titelpre,'') || ' ' || COALESCE(vorname,'') || ' ' || COALESCE(nachname,'') || ' ' || COALESCE(titelpost,'') FROM public.tbl_person WHERE person_id = r.person_id) as recipient, + m.person_id as sender_id, + r.person_id as recipient_id, + MAX(ss.status) as status, + MAX(ss.insertamum) as statusdatum + FROM public.tbl_msg_recipient r + JOIN public.tbl_msg_status ss USING(message_id, person_id) + JOIN public.tbl_msg_message m USING(message_id) + WHERE r.person_id = ? + GROUP BY m.message_id, m.subject, m.body, m.insertamum, m.relationmessage_id, sender, recipient, sender_id, recipient_id + ORDER BY insertamum + "; + + $parametersArray = array($person_id, $person_id); + + return $this->execQuery($sql, $parametersArray); + } } diff --git a/public/css/Studentenverwaltung.css b/public/css/Studentenverwaltung.css index f179c3667..cc2eff51d 100644 --- a/public/css/Studentenverwaltung.css +++ b/public/css/Studentenverwaltung.css @@ -4,6 +4,7 @@ @import './components/FilterComponent.css'; @import './components/Tabs.css'; @import './components/Notiz.css'; +@import './components/Messages.css'; html { font-size: .875em; diff --git a/public/css/components/Messages.css b/public/css/components/Messages.css new file mode 100644 index 000000000..1c004f6b0 --- /dev/null +++ b/public/css/components/Messages.css @@ -0,0 +1,4 @@ +.twoColumns { + height: 400px; + overflow-y: auto; +} diff --git a/public/js/api/messages/person.js b/public/js/api/messages/person.js index bfbdaf123..baf8bd39f 100644 --- a/public/js/api/messages/person.js +++ b/public/js/api/messages/person.js @@ -1,6 +1,5 @@ export default { getMessages(url, config, params){ - console.log("in api", params); return this.$fhcApi.get('api/frontend/v1/messages/messages/getMessages/' + params.id + '/' + params.type); }, } \ No newline at end of file diff --git a/public/js/components/Messages/Details/TableMessages.js b/public/js/components/Messages/Details/TableMessages.js index bc7e6a02a..c4fd4d4d7 100644 --- a/public/js/components/Messages/Details/TableMessages.js +++ b/public/js/components/Messages/Details/TableMessages.js @@ -1,8 +1,12 @@ import {CoreFilterCmpt} from "../../filter/Filter.js"; +import FormForm from '../../Form/Form.js'; +//import FormInput from '../../Form/Input.js'; export default { components: { CoreFilterCmpt, + FormForm, + // FormInput }, props: { endpoint: { @@ -14,6 +18,7 @@ export default { type: [Number, String], required: true }, + messageLayout: String, }, //TODO(Manu) endpoint macht Probleme data(){ @@ -32,12 +37,65 @@ export default { {title: "subject", field: "subject"}, {title: "body", field: "body", visible: false}, {title: "message_id", field: "message_id", visible: false}, - {title: "datum", field: "format_insertamum"}, + { + title: "Datum", + field: "insertamum", + formatter: function (cell) { + const dateStr = cell.getValue(); + const date = new Date(dateStr); // Convert to Date object + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + hour12: false + }); + } + }, {title: "sender", field: "sender"}, {title: "recipient", field: "recipient"}, - {title: "sepersonid", field: "sepersonid"}, - {title: "repersonid", field: "repersonid"}, - {title: "status", field: "status"}, + {title: "senderId", field: "sender_id"}, + {title: "recipientId", field: "recipient_id"}, + { + title: "status", + field: "status", + formatter: function (cell) { + //TODO(Manu) get phrases in this context to work? + + /* const statusMap = { + 0: this.$p.t('messsages', 'unread'), + 1: this.$p.t('messsages', 'read'), + 2: this.$p.t('messsages', 'archived'), + 3: this.$p.t('messsages', 'deleted') + };*/ + const statusMap = { + 0: 'unread', + 1: 'read', + 2: 'archived', + 3: 'deleted' + }; + return statusMap[cell.getValue()]; + // return this.$p.t('messsages', 'deleted'); + } + + }, + { + title: "letzte Änderung", + field: "statusdatum", + formatter: function (cell) { + const dateStr = cell.getValue(); + const date = new Date(dateStr); // Convert to Date object + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + hour12: false + }); + } + }, { title: 'Aktionen', field: 'actions', width: 100, @@ -47,23 +105,23 @@ export default { let button = document.createElement('button'); button.className = 'btn btn-outline-secondary btn-action'; - button.title = this.$p.t('ui', 'notiz_edit'); - button.innerHTML = ''; + button.title = this.$p.t('global', 'reply'); + button.innerHTML = ''; button.addEventListener( 'click', (event) => - this.actionEditNotiz(cell.getData().notiz_id) + this.reply(cell.getData().message_id) ); container.append(button); button = document.createElement('button'); button.className = 'btn btn-outline-secondary btn-action'; - button.title = this.$p.t('notiz', 'notiz_delete'); + button.title = this.$p.t('ui', 'loeschen'); button.innerHTML = ''; button.addEventListener( 'click', () => - this.actionDeleteNotiz(cell.getData().notiz_id) + this.deleteMessage(cell.getData().message_id) ); container.append(button); @@ -71,46 +129,186 @@ export default { }, frozen: true }], - layout: 'fitColumns', - layoutColumnsOnNewData: false, - height: '250', + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + // height: 'auto', + height: '400', + selectable: true, + selectableRangeMode: 'click', +/* layoutColumnsOnNewData: false, + selectableRangeMode: 'click', selectable: true, index: 'message_id', - persistenceID: 'core-message' + persistenceID: 'core-message'*/ }, + tabulatorEvents: [ + { + event: 'dataLoaded', + handler: data => this.tabulatorData = data.map(item => { + return item; + }), + }, + { + event: 'tableBuilt', + handler: async() => { + await this.$p.loadCategory(['global', 'person', 'stv', 'messages', 'ui', 'notiz']); + + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('subject').component.updateDefinition({ + title: this.$p.t('global', 'betreff') + }); + cm.getColumnByField('body').component.updateDefinition({ + title: this.$p.t('messages', 'body') + }); + cm.getColumnByField('message_id').component.updateDefinition({ + title: this.$p.t('messages', 'message_id') + }); + cm.getColumnByField('insertamum').component.updateDefinition({ + title: this.$p.t('global', 'datum') + }); + cm.getColumnByField('sender').component.updateDefinition({ + title: this.$p.t('messages', 'sender') + }); + cm.getColumnByField('recipient').component.updateDefinition({ + title: this.$p.t('messages', 'recipient') + }); + cm.getColumnByField('sender_id').component.updateDefinition({ + title: this.$p.t('messages', 'senderId') + }); + cm.getColumnByField('recipient_id').component.updateDefinition({ + title: this.$p.t('messages', 'recipientId') + }); + cm.getColumnByField('statusdatum').component.updateDefinition({ + title: this.$p.t('notiz', 'letzte_aenderung') + }); + /* + cm.getColumnByField('actions').component.updateDefinition({ + title: this.$p.t('global', 'aktionen') + }); + */ + } + }, + { + event: 'rowClick', + handler: (e, row) => { + const selectedMessage = row.getData().message_id; + const body = row.getData().body; + this.previewBody = body; + console.log(selectedMessage); + } + }, + ], + tabulatorData: [], + previewBody: "" } }, -/* computed: { + methods: { + reply(message_id){ + console.log("in reply " + message_id); + }, + deleteMessage(message_id){ + console.log("deleteMessage " + message_id); + }, + actionNewMessage(){ + console.log("action new message"); + }, + }, + computed: { statusText(){ - 0: this.$p.t('messsages', 'unread'), - 1: this.$p.t('messsages', 'read'), - 2: this.$p.t('messsages', 'archived'), - 0: this.$p.t('messsages', 'unread'), - 3: this.$p.t('person', 'deleted'), + return { + 0: this.$p.t('messsages', 'unread'), + 1: this.$p.t('messsages', 'read'), + 2: this.$p.t('messsages', 'archived'), + 3: this.$p.t('messsages', 'deleted') + } } - },*/ + }, + mounted() { + // change to target="_blank" +/* this.$nextTick(() => { + const links = document.querySelectorAll('.preview a'); + links.forEach(link => { + link.setAttribute('target', '_blank'); + link.setAttribute('rel', 'noopener noreferrer'); // Sicherheitsmaßnahme + }); + });*/ + }, template: `
` diff --git a/public/js/components/Messages/Messages.js b/public/js/components/Messages/Messages.js index 6811a3aed..3fd6e2a02 100644 --- a/public/js/components/Messages/Messages.js +++ b/public/js/components/Messages/Messages.js @@ -17,14 +17,24 @@ export default { required: true }, showNew: Boolean, - showTable: Boolean + showTable: Boolean, + messageLayout: { + type: String, + default: 'twoColumnsTableLeft', + validator(value) { + return [ + 'twoColumnsTableLeft', + 'listTableTop' + ].includes(value) + } + }, }, data() { return {} }, template: `