From d549aee42c5b77d912f2d222768f87cdc6547e61 Mon Sep 17 00:00:00 2001 From: rdkartono Date: Thu, 9 Oct 2025 15:49:03 +0700 Subject: [PATCH] commit 09/10/2025 User Management belum kelar --- html/webpage/assets/css/bss-overrides.css | 39 ++ html/webpage/assets/css/styles.css | 50 +- html/webpage/assets/js/broadcastzones.js | 59 ++- html/webpage/assets/js/bs-init.js | 7 + html/webpage/assets/js/languagelink.js | 62 ++- html/webpage/assets/js/messagebank.js | 67 ++- html/webpage/assets/js/schedulebank.js | 82 +-- html/webpage/assets/js/script.js | 265 +--------- html/webpage/assets/js/soundbank.js | 92 +++- html/webpage/assets/js/soundchannel.js | 49 +- html/webpage/assets/js/usermanagement.js | 517 ++++++++++++++++++- html/webpage/broadcastzones.html | 12 +- html/webpage/home.html | 2 + html/webpage/language.html | 8 +- html/webpage/log.html | 4 +- html/webpage/login.html | 2 + html/webpage/messagebank.html | 42 +- html/webpage/overview.html | 10 +- html/webpage/setting.html | 4 +- html/webpage/soundbank.html | 10 +- html/webpage/streamerstatus.html | 4 +- html/webpage/timer.html | 10 +- html/webpage/usermanagement.html | 98 +++- src/Main.kt | 2 +- src/codes/Somecodes.kt | 17 + src/database/MariaDB.kt | 77 ++- src/database/UserDB.kt | 16 + src/web/KeyValueMessage.kt | 4 + src/web/WebApp.kt | 586 +++++++++++++++++----- 29 files changed, 1535 insertions(+), 662 deletions(-) create mode 100644 html/webpage/assets/css/bss-overrides.css create mode 100644 html/webpage/assets/js/bs-init.js create mode 100644 src/web/KeyValueMessage.kt diff --git a/html/webpage/assets/css/bss-overrides.css b/html/webpage/assets/css/bss-overrides.css new file mode 100644 index 0000000..d06cc3c --- /dev/null +++ b/html/webpage/assets/css/bss-overrides.css @@ -0,0 +1,39 @@ +:root, [data-bs-theme=light] { + --bs-primary: #0d6efd; + --bs-primary-rgb: 13,110,253; + --bs-primary-text-emphasis: #052C65; + --bs-primary-bg-subtle: #CFE2FF; + --bs-primary-border-subtle: #9EC5FE; +} + +.btn-primary { + --bs-btn-color: #fff; + --bs-btn-bg: #0d6efd; + --bs-btn-border-color: #0d6efd; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0B5ED7; + --bs-btn-hover-border-color: #0A58CA; + --bs-btn-focus-shadow-rgb: 219,233,255; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #0A58CA; + --bs-btn-active-border-color: #0A53BE; + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #0d6efd; + --bs-btn-disabled-border-color: #0d6efd; +} + +.btn-outline-primary { + --bs-btn-color: #0d6efd; + --bs-btn-border-color: #0d6efd; + --bs-btn-focus-shadow-rgb: 13,110,253; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0d6efd; + --bs-btn-hover-border-color: #0d6efd; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #0d6efd; + --bs-btn-active-border-color: #0d6efd; + --bs-btn-disabled-color: #0d6efd; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0d6efd; +} + diff --git a/html/webpage/assets/css/styles.css b/html/webpage/assets/css/styles.css index 06d32fc..0c12988 100644 --- a/html/webpage/assets/css/styles.css +++ b/html/webpage/assets/css/styles.css @@ -62,9 +62,9 @@ body { .btn-round-basic:focus { background-color: #f5f5f5; - border-radius: 20px; + border-radius: 8px; box-shadow: inset 4px 4px 10px #88a5bf7b, inset -4px -4px 10px #ffffff; - color: #4d4d4d; + /*color: #4d4d4d;*/ cursor: pointer; font-size: 16px; transition: all 0.2s ease-in-out; @@ -72,7 +72,7 @@ body { } .btn-round-basic { - border-radius: 20px; + border-radius: 08px; box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px; --bs-btn-hover-bg: #ffffff; } @@ -82,24 +82,24 @@ body { box-shadow: inset 2px 2px 5px #bcbcbc, inset -2px -2px 5px #ffffff, 2px 2px 5px #bcbcbc, -2px -2px 5px #ffffff; } -.color-import { +.color-import, .color-import:hover, .color-import:focus { color: var(--bs-teal); } -.color-remove { +.color-remove, .color-remove:hover, .color-remove:focus { color: var(--bs-danger); } -.color-edit { +.color-edit, .color-edit:hover, .color-edit:focus { color: var(--bs-primary-text-emphasis); } -.color-add { +.color-add, .color-add:hover, .color-add:focus { color: var(--bs-primary); } .input-login { - border-radius: 50px; + border-radius: 8px; box-shadow: rgba(9, 30, 66, 0.25) 0px 4px 8px -2px, rgba(9, 30, 66, 0.08) 0px 0px 0px 1px; } @@ -227,25 +227,23 @@ nav-item:focus { } .accordion-item.active { - /*background: rgba(45, 53, 120, 0.15);*/ - /*box-shadow: inset 4px 4px 10px rgba(45, 53, 120, 0.25), inset -4px -4px 10px rgba(255, 255, 255, 0.8);*/ + background: rgba(45, 53, 120, 0.15); + box-shadow: inset 4px 4px 10px rgba(45, 53, 120, 0.25), inset -4px -4px 10px rgba(255, 255, 255, 0.8); } .bg-accordion { border: white 2px; - /*border-radius: 10px;*/ + border-radius: 8px; background: #f8f9fd; } .card-channel { - border-radius: 12px; + border-radius: 8px; background: #ffffff; backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); transition: transform 0.2s ease, box-shadow 0.2s ease; border: #ffffff solid 2px !important; - /*padding-left: 2px;*/ - /*padding-right: 5px;*/ padding-top: 12px; padding-bottom: 12px; } @@ -255,3 +253,27 @@ nav-item:focus { border: white solid 3px; } +.progress-bar { + background-color: #172066; +} + +table { + border-radius: 8px; +} + +.bg-modal-body { + background-color: #f8f9fd; +} + +.bg-header-modal { + background-color: #f0f2ff; +} + +.pad-row-btn { + margin: 0.5rem; +} + +.pad-2 { + border-radius: 0 !important; +} + diff --git a/html/webpage/assets/js/broadcastzones.js b/html/webpage/assets/js/broadcastzones.js index 5a2c07f..f3bf763 100644 --- a/html/webpage/assets/js/broadcastzones.js +++ b/html/webpage/assets/js/broadcastzones.js @@ -1,4 +1,17 @@ +/** + * @typedef {Object} BroadcastZone + * @property {number} index + * @property {string} description + * @property {String} SoundChannel + * @property {String} Box + * @property {String} Relay + */ +/** + * List of broadcast zones available + * @type {BroadcastZone[]} + */ +window.BroadcastZoneList ??= []; /** * Currently selected broadcast zone row in the table @@ -42,7 +55,22 @@ function fill_broadcastzonetablebody(vv) { $('#tablesize').text("Table Size: " + vv.length); } - +/** + * Reload broadcast zones from server + * @param {String} APIURL API URL endpoint (default "BroadcastZones/") + */ +function reloadBroadcastZones(APIURL = "BroadcastZones/") { + window.BroadcastZoneList = []; + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + //console.log("reloadBroadcastZones : ", okdata) + window.BroadcastZoneList.push(...okdata); + fill_broadcastzonetablebody(window.BroadcastZoneList); + } else console.log("reloadBroadcastZones: okdata is not array"); + }, (errdata) => { + alert("Error loading broadcast zones : " + errdata.message); + }); +} $(document).ready(function () { console.log("broadcastzones.js loaded successfully"); @@ -112,14 +140,11 @@ $(document).ready(function () { } } - reloadBroadcastZones(APIURL_BroadcastZone, () => { - fill_broadcastzonetablebody(window.BroadcastZoneList); - }); + reloadBroadcastZones(APIURL_BroadcastZone); $btnClear.click(() => { DoClear(APIURL_BroadcastZone, "BroadcastZones", (okdata) => { reloadBroadcastZones(APIURL_BroadcastZone); - fill_broadcastzonetablebody(window.BroadcastZoneList); alert("Success clear broadcast zones: " + okdata.message); }, (errdata) => { alert("Error clear broadcast zones: " + errdata.message); @@ -165,10 +190,8 @@ $(document).ready(function () { Relay: relay }; fetchAPI(APIURL_BroadcastZone + "Add", "POST", {}, bz, (okdata) => { - reloadBroadcastZones(APIURL_BroadcastZone, () => { - fill_broadcastzonetablebody(window.BroadcastZoneList); - alert("Success add new broadcast zone: " + okdata.message); - }); + reloadBroadcastZones(APIURL_BroadcastZone); + alert("Success add new broadcast zone: " + okdata.message); }, (errdata) => { alert("Error add new broadcast zone: " + errdata.message); }); @@ -193,10 +216,8 @@ $(document).ready(function () { }; if (confirm(`Are you sure to delete broadcast zone [${bz.index}] Description=${bz.description}?`)) { fetchAPI(APIURL_BroadcastZone + "DeleteByIndex/" + bz.index, "DELETE", {}, null, (okdata) => { - reloadBroadcastZones(APIURL_BroadcastZone, () => { - fill_broadcastzonetablebody(window.BroadcastZoneList); - alert("Success delete broadcast zone: " + okdata.message); - }); + reloadBroadcastZones(APIURL_BroadcastZone); + alert("Success delete broadcast zone: " + okdata.message); }, (errdata) => { alert("Error delete broadcast zone: " + errdata.message); }); @@ -262,10 +283,8 @@ $(document).ready(function () { Relay: relay }; fetchAPI(APIURL_BroadcastZone + "UpdateByIndex/" + bz.index, "PATCH", {}, bzUpdate, (okdata) => { - reloadBroadcastZones(APIURL_BroadcastZone, () => { - fill_broadcastzonetablebody(window.BroadcastZoneList); - alert("Success edit broadcast zone: " + okdata.message); - }); + reloadBroadcastZones(APIURL_BroadcastZone); + alert("Success edit broadcast zone: " + okdata.message); }, (errdata) => { alert("Error edit broadcast zone: " + errdata.message); }); @@ -284,10 +303,8 @@ $(document).ready(function () { $btnImport.click(() => { DoImport(APIURL_BroadcastZone, (okdata) => { - reloadBroadcastZones(APIURL_BroadcastZone, () => { - fill_broadcastzonetablebody(window.BroadcastZoneList); - alert("Success import broadcast zones: " + okdata.message); - }); + reloadBroadcastZones(APIURL_BroadcastZone); + alert("Success import broadcast zones: " + okdata.message); }, (errdata) => { alert("Error importing broadcast zones from XLSX: " + errdata.message); }); diff --git a/html/webpage/assets/js/bs-init.js b/html/webpage/assets/js/bs-init.js new file mode 100644 index 0000000..3c1498d --- /dev/null +++ b/html/webpage/assets/js/bs-init.js @@ -0,0 +1,7 @@ +document.addEventListener('DOMContentLoaded', function() { + + var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bss-tooltip]')); + var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { + return new bootstrap.Tooltip(tooltipTriggerEl); + }) +}, false); \ No newline at end of file diff --git a/html/webpage/assets/js/languagelink.js b/html/webpage/assets/js/languagelink.js index 8bdd05d..d48b31c 100644 --- a/html/webpage/assets/js/languagelink.js +++ b/html/webpage/assets/js/languagelink.js @@ -1,4 +1,15 @@ +/** + * @typedef {Object} LanguageBank + * @property {number} index + * @property {string} tag + * @property {string} language + * + */ +/** List of Languagebank data loaded from server + * @type {LanguageBank[]} + */ +window.languagebankdata = []; /** * Currently selected languagebank row in the table * @type {JQuery|null} @@ -39,7 +50,22 @@ function fill_languagebanktablebody(vv) { $('#tablesize').text("Table Size: " + vv.length); } - +/** + * Reload language bank from server + * @param {string} APIURL API URL endpoint, default "LanguageLink/" + */ +function reloadLanguageBank(APIURL = "LanguageLink/") { + window.languagebankdata = []; + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + window.languagebankdata.push(...okdata); + window.selectedlanguagerow = null; + fill_languagebanktablebody(window.languagebankdata); + } + }, (errdata) => { + alert("Error loading languagebank : " + errdata.message); + }); +} $(document).ready(function () { console.log('languagebank.js loaded'); @@ -89,15 +115,11 @@ $(document).ready(function () { } }); - reloadLanguageBank(APIURL, () => { - fill_languagebanktablebody(window.languagebankdata); - }); + reloadLanguageBank(APIURL); $btnClear.click(() => { DoClear(APIURL, "LanguageLink", (okdata) => { - reloadLanguageBank(APIURL, () => { - fill_languagebanktablebody(window.languagebankdata); - alert("Success clear languageLink : " + okdata.message); - }); + reloadLanguageBank(APIURL); + alert("Success clear languageLink : " + okdata.message); }, (errdata) => { alert("Error clear languageLink : " + errdata.message); }); @@ -134,10 +156,8 @@ $(document).ready(function () { language: langString } fetchAPI(APIURL + "Add", "POST", {}, ll, (okdata) => { - reloadLanguageBank(APIURL, () => { - fill_languagebanktablebody(window.languagebankdata); - alert("Success add language : " + okdata.message); - }); + alert("Success add language : " + okdata.message); + reloadLanguageBank(APIURL); }, (errdata) => { alert("Error add language : " + errdata.message); }); @@ -161,10 +181,8 @@ $(document).ready(function () { } if (confirm(`Are you sure to delete language [${ll.index}] Tag=${ll.tag} Language=${ll.language}?`)) { fetchAPI(APIURL + "DeleteByIndex/" + ll.index, "DELETE", {}, null, (okdata) => { - reloadLanguageBank(APIURL, () => { - fill_languagebanktablebody(window.languagebankdata); - alert("Success delete language : " + okdata.message); - }); + reloadLanguageBank(APIURL); + alert("Success delete language : " + okdata.message); }, (errdata) => { alert("Error delete language : " + errdata.message); }); @@ -221,10 +239,8 @@ $(document).ready(function () { ll.tag = tag; ll.language = langString; fetchAPI(APIURL + "UpdateByIndex/" + ll.index, "PATCH", {}, ll, (okdata) => { - reloadLanguageBank(APIURL, () => { - fill_languagebanktablebody(window.languagebankdata); - alert("Success edit language : " + okdata.message); - }); + reloadLanguageBank(APIURL); + alert("Success edit language : " + okdata.message); }, (errdata) => { alert("Error edit language : " + errdata.message); }); @@ -246,10 +262,8 @@ $(document).ready(function () { }); $btnImport.click(() => { DoImport(APIURL, (okdata) => { - reloadLanguageBank(APIURL, () => { - fill_languagebanktablebody(window.languagebankdata); - alert("Success import languagebank : " + okdata.message); - }); + reloadLanguageBank(APIURL); + alert("Success import languagebank : " + okdata.message); }, (errdata) => { alert("Error importing languagebank from XLSX : " + errdata.message); }); diff --git a/html/webpage/assets/js/messagebank.js b/html/webpage/assets/js/messagebank.js index 4211edb..1acf321 100644 --- a/html/webpage/assets/js/messagebank.js +++ b/html/webpage/assets/js/messagebank.js @@ -1,4 +1,19 @@ +/** + * @typedef {Object} MessageBank + * @property {number} index + * @property {string} description + * @property {string} language + * @property {number} aNN_ID + * @property {string} voice_Type + * @property {string} message_Detail + * @property {string} message_TAGS + */ +/** + * List of Messagebank data loaded from server + * @type {MessageBank[]} + */ +window.messagebankdata ??= []; /** * Currently selected messagebank row in the table * @type {JQuery|null} @@ -44,7 +59,22 @@ function fill_messagebanktablebody(vv) { $('#tablesize').text("Table Size: " + vv.length); } - +/** +* Reload message bank from server +* @param {string} APIURL API URL endpoint, default "MessageBank/" +*/ +function reloadMessageBank(APIURL = "MessageBank/") { + window.messagebankdata ??= []; + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + window.messagebankdata.push(...okdata); + window.selectedmessagerow = null; + fill_messagebanktablebody(window.messagebankdata); + } + }, (errdata) => { + alert("Error loading messagebank : " + errdata.message); + }); +} $(document).ready(function () { console.log("messagebank.js loaded"); @@ -178,15 +208,11 @@ $(document).ready(function () { }); - reloadMessageBank(APIURL, () => { - fill_messagebanktablebody(window.messagebankdata); - }); + reloadMessageBank(APIURL); $btnClear.click(() => { DoClear(APIURL, "Messagebank", (okdata) => { - reloadMessageBank(APIURL, () => { - fill_messagebanktablebody(window.messagebankdata); - alert("Success clear messagebank : " + okdata.message); - }); + reloadMessageBank(APIURL); + alert("Success clear messagebank : " + okdata.message); }, (errdata) => { alert("Error clear messagebank : " + errdata.message); }); @@ -261,10 +287,8 @@ $(document).ready(function () { }; // send to server using fetchAPI fetchAPI(APIURL + "Add", "POST", mb, null, (okdata) => { - reloadMessageBank(APIURL, () => { - fill_messagebanktablebody(window.messagebankdata); - alert("Success add new messagebank : " + okdata.message); - }); + reloadMessageBank(APIURL); + alert("Success add new messagebank : " + okdata.message); }, (errdata) => { alert("Error add new messagebank : " + errdata.message); }); @@ -292,10 +316,8 @@ $(document).ready(function () { if (confirm(`Are you sure to delete messagebank [${mb.index}] Description=${mb.description}? ANN_ID=${mb.aNN_ID} Language=${mb.language} Voice_Type=${mb.voice_Type} `)) { fetchAPI(APIURL + "DeleteByIndex/" + mb.index, "DELETE", {}, null, (okdata) => { - reloadMessageBank(APIURL, () => { - fill_messagebanktablebody(window.messagebankdata); - alert("Success delete messagebank : " + okdata.message); - }); + reloadMessageBank(APIURL); + alert("Success delete messagebank : " + okdata.message); }, (errdata) => { alert("Error delete messagebank : " + errdata.message); }); @@ -401,10 +423,8 @@ $(document).ready(function () { Message_TAGS: messagetags }; fetchAPI(APIURL + "UpdateByIndex/" + mb.index, "PATCH", mbUpdate, null, (okdata) => { - reloadMessageBank(APIURL, () => { - fill_messagebanktablebody(window.messagebankdata); - alert("Success edit messagebank : " + okdata.message); - }); + reloadMessageBank(APIURL); + alert("Success edit messagebank : " + okdata.message); }, (errdata) => { alert("Error edit messagebank : " + errdata.message); }); @@ -423,11 +443,8 @@ $(document).ready(function () { }); $btnImport.click(() => { DoImport(APIURL, (okdata) => { - reloadMessageBank(APIURL, () => { - fill_messagebanktablebody(window.messagebankdata); - alert("Success import messagebank : " + okdata.message); - }); - + reloadMessageBank(APIURL); + alert("Success import messagebank : " + okdata.message); }, (errdata) => { alert("Error importing messagebank from XLSX : " + errdata.message); }); diff --git a/html/webpage/assets/js/schedulebank.js b/html/webpage/assets/js/schedulebank.js index 7a9bade..6c9e437 100644 --- a/html/webpage/assets/js/schedulebank.js +++ b/html/webpage/assets/js/schedulebank.js @@ -1,4 +1,20 @@ +/** + * @typedef {Object} ScheduleBank + * @property {number} index + * @property {string} description + * @property {string} day + * @property {string} time + * @property {string} soundpath + * @property {number} repeat + * @property {boolean} enable + * @property {string} broadcastZones + * @property {string} language + */ +/** List of Schedulebank data loaded from server + * @type {ScheduleBank[]} + */ +window.schedulebankdata = []; /** * Currently selected schedulebank row in the table * @type {JQuery|null} @@ -45,7 +61,22 @@ function fill_schedulebanktablebody(vv) { $('#tablesize').text("Table Size: " + vv.length); } - +/** + * Reload timer bank from server + * @param {string} APIURL API URL endpoint, default "ScheduleBank/" + */ +function reloadTimerBank(APIURL = "ScheduleBank/") { + window.schedulebankdata = []; + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + window.schedulebankdata.push(...okdata); + selectedschedulerow = null; + fill_schedulebanktablebody(window.schedulebankdata); + } + }, (errdata) => { + alert("Error loading schedulebank : " + errdata.message); + }); +} $(document).ready(function () { console.log("schedulebank.js loaded successfully"); @@ -70,7 +101,7 @@ $(document).ready(function () { let $schedulehour = $schedulemodal.find('#schedulehour'); // number input 0-59 let $scheduleminute = $schedulemodal.find('#scheduleminute'); - // select for messagebank + // text input let $schedulesoundpath = $schedulemodal.find('#schedulesoundpath'); // number input 0-5 let $schedulerepeat = $schedulemodal.find('#schedulerepeat'); @@ -106,17 +137,8 @@ $(document).ready(function () { $scheduledescription.val(''); $schedulehour.val('0'); $scheduleminute.val('0'); - - $schedulesoundpath.empty(); - if (Array.isArray(window.messagebankdata) && window.messagebankdata.length > 0) { - window.messagebankdata.forEach(item => { - let str = item.description+" ["+item.aNN_ID+"]"; - let option = ``; - if ($schedulesoundpath.find(`option[value="${str}"]`).length === 0) $schedulesoundpath.append(option); // check if $schedulesoundpath already has this option - }) - } - - $schedulerepeat.val('1'); + $schedulesoundpath.val(''); + $schedulerepeat.val('0'); $scheduleenable.prop('checked', true); $scheduleeveryday.prop('checked', false); $schedulesunday.prop('checked', false); @@ -149,15 +171,11 @@ $(document).ready(function () { }); - reloadTimerBank(APIURL, () => { - fill_schedulebanktablebody(window.schedulebankdata); - }); + reloadTimerBank(APIURL); $btnClear.click(() => { DoClear(APIURL, "Timerbank", (okdata) => { - reloadTimerBank(APIURL,() => { - fill_schedulebanktablebody(window.schedulebankdata); - alert("Success clear schedulebank : " + okdata.message); - }); + reloadTimerBank(APIURL); + alert("Success clear schedulebank : " + okdata.message); }, (errdata) => { alert("Error clear schedulebank : " + errdata.message); }); @@ -218,10 +236,8 @@ $(document).ready(function () { }; fetchAPI(APIURL + "Add", "POST", {}, scheduleObj, (okdata) => { - reloadTimerBank(APIURL, () => { - fill_schedulebanktablebody(window.schedulebankdata); - alert("Success add schedule: " + okdata.message); - }); + alert("Success add schedule: " + okdata.message); + reloadTimerBank(APIURL); }, (errdata) => { alert("Error add schedule: " + errdata.message); }); @@ -246,10 +262,8 @@ $(document).ready(function () { } if (confirm(`Are you sure to delete schedule [${sr.index}] Description=${sr.description}?`)) { fetchAPI(APIURL + "DeleteByIndex/" + sr.index, "DELETE", {}, null, (okdata) => { - reloadTimerBank(APIURL, () => { - fill_schedulebanktablebody(window.schedulebankdata); - alert("Success delete schedule : " + okdata.message); - }); + reloadTimerBank(APIURL); + alert("Success delete schedule : " + okdata.message); }, (errdata) => { alert("Error delete schedule : " + errdata.message); }); @@ -366,10 +380,8 @@ $(document).ready(function () { }; fetchAPI(APIURL + "UpdateByIndex/" + sr.index, "PATCH", {}, scheduleObj, (okdata) => { - reloadTimerBank(APIURL, () => { - fill_schedulebanktablebody(window.schedulebankdata); - alert("Success edit schedule: " + okdata.message); - }); + alert("Success edit schedule: " + okdata.message); + reloadTimerBank(APIURL); }, (errdata) => { alert("Error edit schedule: " + errdata.message); }); @@ -384,10 +396,8 @@ $(document).ready(function () { }); $btnImport.click(() => { DoImport(APIURL, (okdata) => { - reloadTimerBank(APIURL, () => { - fill_schedulebanktablebody(window.schedulebankdata); - alert("Success import schedulebank from XLSX : " + okdata.message); - }); + reloadTimerBank(APIURL); + alert("Success import schedulebank from XLSX : " + okdata.message); }, (errdata) => { alert("Error importing schedulebank from XLSX : " + errdata.message); }); diff --git a/html/webpage/assets/js/script.js b/html/webpage/assets/js/script.js index d73218b..7f0b14a 100644 --- a/html/webpage/assets/js/script.js +++ b/html/webpage/assets/js/script.js @@ -20,263 +20,6 @@ window.languages = []; */ window.scheduledays = [] -/** - * @typedef {Object} MessageBank - * @property {number} index - * @property {string} description - * @property {string} language - * @property {number} aNN_ID - * @property {string} voice_Type - * @property {string} message_Detail - * @property {string} message_TAGS - */ - -/** - * List of Messagebank data loaded from server - * taruh di sini karena dipakai di banyak tempat - * @type {MessageBank[]} - */ -window.messagebankdata ??= []; - -/** -* Reload message bank from server -* @param {string} APIURL API URL endpoint, default "MessageBank/" -* @param {Function|null} callback Optional callback function to execute after loading -*/ -function reloadMessageBank(APIURL = "MessageBank/", callback=null) { - window.messagebankdata ??= []; - fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { - if (Array.isArray(okdata)) { - window.messagebankdata.push(...okdata); - console.log("Loaded " + window.messagebankdata.length + " message bank items"); - window.selectedmessagerow = null; - if (callback && typeof callback === 'function') callback(); - } - }, (errdata) => { - alert("Error loading messagebank : " + errdata.message); - }); -} - -/** - * @typedef {Object} ScheduleBank - * @property {number} index - * @property {string} description - * @property {string} day - * @property {string} time - * @property {string} soundpath - * @property {number} repeat - * @property {boolean} enable - * @property {string} broadcastZones - * @property {string} language - */ - -/** List of Schedulebank data loaded from server - * @type {ScheduleBank[]} - */ -window.schedulebankdata = []; - -/** - * Reload timer bank from server - * taruh di sini karena dipakai di banyak tempat - * @param {string} APIURL API URL endpoint, default "ScheduleBank/" - * @param {Function|null} callback Optional callback function to execute after loading - */ -function reloadTimerBank(APIURL = "ScheduleBank/", callback=null) { - window.schedulebankdata = []; - fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { - if (Array.isArray(okdata)) { - window.schedulebankdata.push(...okdata); - selectedschedulerow = null; - console.log("Loaded " + window.schedulebankdata.length + " schedule bank items"); - if (callback && typeof callback === 'function') callback(); - } - }, (errdata) => { - alert("Error loading schedulebank : " + errdata.message); - }); -} - -/** - * @typedef {Object} BroadcastZone - * @property {number} index - * @property {string} description - * @property {String} SoundChannel - * @property {String} Box - * @property {String} Relay - */ - -/** - * List of broadcast zones available - * @type {BroadcastZone[]} - */ -window.BroadcastZoneList ??= []; - -/** - * Reload broadcast zones from server - * taruh di sini karena dipakai di banyak tempat - * @param {String} APIURL API URL endpoint (default "BroadcastZones/") - * @param {Function|null} callback Optional callback function to execute after loading - */ -function reloadBroadcastZones(APIURL = "BroadcastZones/", callback=null) { - window.BroadcastZoneList = []; - fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { - if (Array.isArray(okdata)) { - //console.log("reloadBroadcastZones : ", okdata) - window.BroadcastZoneList.push(...okdata); - console.log("Loaded " + window.BroadcastZoneList.length + " broadcast zone items"); - window.selectedbroadcastzonerow = null; - if (callback && typeof callback === 'function') callback(); - } else console.log("reloadBroadcastZones: okdata is not array"); - }, (errdata) => { - alert("Error loading broadcast zones : " + errdata.message); - }); -} - -/** - * @typedef {Object} SoundBank - * @property {number} index - * @property {string} description - * @property {string} tag - * @property {string} category - * @property {string} language - * @property {string} voiceType - * @property {string} path - */ - -/** - * @typedef {Object} Select2item - * @property {number} id - * @property {string} text - */ - -/** - * List of Soundbank data loaded from server - * taruh di sini karena dipakai di banyak tempat - * @type {SoundBank[]} - */ -window.soundbankdata = []; - -/** - * List of sound files in the soundbank directory, that ends with .wav or .mp3 - * taruh di sini karena dipakai di banyak tempat - * @type {string[]} - */ -window.soundbankfiles = []; - -/** - * Select2 data source - * See https://select2.org/data-sources/formats - * @type {Select2item[]} - */ -window.select2data = []; - - - -/** - * Reload sound bank from server - * @param {String} APIURL API URL endpoint, default "SoundBank/" - * @param {Function|null} callback Optional callback function to execute after loading - */ -function reloadSoundBank(APIURL = "SoundBank/", callback=null) { - window.soundbankdata = []; - fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { - - if (Array.isArray(okdata)) { - window.soundbankdata.push(...okdata); - window.selectedsoundrow = null; - console.log("Loaded " + window.soundbankdata.length + " sound bank items"); - if (callback && typeof callback === 'function') callback(); - } - }, (errdata) => { - alert("Error loading soundbank : " + errdata.message); - }); -} - -/** - * Reload soundbank files from server - * @param {String} APIURL API URL endpoint (default "SoundBank/") - * @param {Function|null} callback Optional callback function to execute after loading - */ -function reloadSoundbankFiles(APIURL = "SoundBank/",callback=null) { - window.soundbankfiles = []; - fetchAPI(APIURL + "ListFiles", "GET", {}, null, (okdata) => { - // okdata is a string contains elements separated by semicolon ; - if (Array.isArray(okdata)) { - window.soundbankfiles = okdata.filter(item => item.trim().length > 0); - // refill select2data - window.select2data = window.soundbankfiles.map((item, index) => ({ id: index + 1, text: item })); - console.log("Loaded " + window.soundbankfiles.length + " sound bank files"); - if (callback && typeof callback === 'function') callback(); - } else console.log("reloadSoundbankFiles: okdata is not array"); - }, (errdata) => { - alert("Error loading soundbank files : " + errdata.message); - }); -} - -/** - * @typedef {Object} SoundChannel - * @property {number} index - The index of the sound channel. - * @property {string} channel - The name of the sound channel. - * @property {string} ip - The IP address associated with the sound channel. - */ - -/** - * @type {SoundChannel[]} - */ -window.soundChannels = []; - -/** - * Reload sound channels from server - * @param {String} APIURL API URL endpoint (default "SoundChannel/") - * @param {Function|null} callback Optional callback function to execute after loading - */ -function reloadSoundChannel(APIURL = "SoundChannel/", callback=null) { - window.soundChannels = []; - fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { - if (Array.isArray(okdata)) { - //console.log("reloadSoundChannel : ", okdata) - window.soundChannels.push(...okdata); - window.selectedsoundchannelrow = null; - console.log("Loaded " + window.soundChannels.length + " sound channel items"); - if (callback && typeof callback === 'function') callback(); - } else console.log("reloadSoundChannel: okdata is not array"); - }, (errdata) => { - alert("Error loading sound channels : " + errdata.message); - }); -} - -/** - * @typedef {Object} LanguageBank - * @property {number} index - * @property {string} tag - * @property {string} language - * - */ - -/** List of Languagebank data loaded from server - * @type {LanguageBank[]} - */ -window.languagebankdata = []; - -/** - * Reload language bank from server - * @param {string} APIURL API URL endpoint, default "LanguageLink/" - * @param {Function|null} callback Optional callback function to execute after loading - */ -function reloadLanguageBank(APIURL = "LanguageLink/", callback=null) { - window.languagebankdata = []; - fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { - if (Array.isArray(okdata)) { - window.languagebankdata.push(...okdata); - window.selectedlanguagerow = null; - console.log("Loaded " + window.languagebankdata.length + " language bank items"); - if (callback && typeof callback === 'function') callback(); - } - }, (errdata) => { - alert("Error loading languagebank : " + errdata.message); - }); -} - - /** * Create a list item element * @param {String} text Text Content for the list item @@ -568,13 +311,7 @@ $(document).ready(function () { getCategories(); getLanguages(); getScheduledDays(); - reloadMessageBank(); - reloadTimerBank(); - reloadBroadcastZones(); - reloadSoundBank(); - reloadSoundbankFiles(); - reloadSoundChannel(); - reloadLanguageBank(); + // Initialize WebSocket connection window.ws = new WebSocket(wsURL); diff --git a/html/webpage/assets/js/soundbank.js b/html/webpage/assets/js/soundbank.js index 855c951..59ecfb7 100644 --- a/html/webpage/assets/js/soundbank.js +++ b/html/webpage/assets/js/soundbank.js @@ -1,11 +1,61 @@ +/** + * @typedef {Object} SoundBank + * @property {number} index + * @property {string} description + * @property {string} tag + * @property {string} category + * @property {string} language + * @property {string} voiceType + * @property {string} path + */ +/** + * @typedef {Object} Select2item + * @property {number} id + * @property {string} text + */ + +/** + * List of Soundbank data loaded from server + * @type {SoundBank[]} + */ +window.soundbankdata = []; /** * Currently selected soundbank row in the table * @type {JQuery|null} */ window.selectedsoundrow = null; +/** + * List of sound files in the soundbank directory, that ends with .wav or .mp3 + * @type {string[]} + */ +window.soundbankfiles = []; +/** + * Select2 data source + * See https://select2.org/data-sources/formats + * @type {Select2item[]} + */ +window.select2data = []; + +/** + * Reload sound bank from server + * @param {String} APIURL API URL endpoint, default "SoundBank/" + */ +function reloadSoundBank(APIURL = "SoundBank/") { + window.soundbankdata = []; + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + + if (Array.isArray(okdata)) { + window.soundbankdata.push(...okdata); + window.selectedsoundrow = null; + fill_soundbanktablebody(window.soundbankdata); + } + }, (errdata) => { + alert("Error loading soundbank : " + errdata.message); + }); +} /** * Fill soundbank table body with values @@ -13,7 +63,6 @@ window.selectedsoundrow = null; */ function fill_soundbanktablebody(vv) { $('#soundbanktablebody').empty(); - console.log("Filling soundbank table with " + vv.length + " items"); if (!Array.isArray(vv) || vv.length === 0) return; vv.forEach(item => { const row = ` @@ -49,7 +98,23 @@ function fill_soundbanktablebody(vv) { } - +/** + * Reload soundbank files from server + * @param {String} APIURL API URL endpoint (default "SoundBank/") + */ +function reloadSoundbankFiles(APIURL = "SoundBank/") { + window.soundbankfiles = []; + fetchAPI(APIURL + "ListFiles", "GET", {}, null, (okdata) => { + // okdata is a string contains elements separated by semicolon ; + if (Array.isArray(okdata)) { + window.soundbankfiles = okdata.filter(item => item.trim().length > 0); + // refill select2data + window.select2data = window.soundbankfiles.map((item, index) => ({ id: index + 1, text: item })); + } else console.log("reloadSoundbankFiles: okdata is not array"); + }, (errdata) => { + alert("Error loading soundbank files : " + errdata.message); + }); +} $(document).ready(function () { console.log("soundbank.js loaded successfully"); @@ -107,10 +172,7 @@ $(document).ready(function () { }) } - reloadSoundBank(APIURL, () => { - fill_soundbanktablebody(window.soundbankdata); - }); - + reloadSoundBank(APIURL); $('#findsoundbank').on('input', function () { let searchTerm = $(this).val().trim().toLowerCase(); if (searchTerm.length > 0) { @@ -124,10 +186,8 @@ $(document).ready(function () { }); $btnClear.click(() => { DoClear(APIURL, "Soundbank", (okdata) => { - reloadSoundBank(APIURL, () => { - fill_soundbanktablebody(window.soundbankdata); - alert("Success clear soundbank : " + okdata.message); - }); + reloadSoundBank(APIURL); + alert("Success clear soundbank : " + okdata.message); }, (errdata) => { alert("Error clear soundbank : " + errdata.message); }); @@ -162,10 +222,8 @@ $(document).ready(function () { } if (confirm(`Are you sure to delete soundbank [${sb.index}] Description=${sb.description} Tag=${sb.tag}?`)) { fetchAPI(APIURL + "DeleteByIndex/" + sb.index, "DELETE", {}, null, (okdata) => { - reloadSoundBank(APIURL, () => { - fill_soundbanktablebody(window.soundbankdata); - alert("Success delete soundbank : " + okdata.message); - }); + reloadSoundBank(APIURL); + alert("Success delete soundbank : " + okdata.message); }, (errdata) => { alert("Error delete soundbank : " + errdata.message); }); @@ -207,10 +265,8 @@ $(document).ready(function () { }); $btnImport.click(() => { DoImport(APIURL, (okdata) => { - reloadSoundBank(APIURL, () => { - fill_soundbanktablebody(window.soundbankdata); - alert("Success import soundbank : " + okdata.message); - }); + reloadSoundBank(APIURL); + alert("Success import soundbank : " + okdata.message); }, (errdata) => { alert("Error importing soundbank from XLSX : " + errdata.message); }); diff --git a/html/webpage/assets/js/soundchannel.js b/html/webpage/assets/js/soundchannel.js index a273349..2935eac 100644 --- a/html/webpage/assets/js/soundchannel.js +++ b/html/webpage/assets/js/soundchannel.js @@ -1,4 +1,14 @@ +/** + * @typedef {Object} SoundChannel + * @property {number} index - The index of the sound channel. + * @property {string} channel - The name of the sound channel. + * @property {string} ip - The IP address associated with the sound channel. + */ +/** + * @type {SoundChannel[]} + */ +window.soundChannels = []; // Currently selected sound channel row in the table window.selectedSoundChannel = null; @@ -41,7 +51,22 @@ function fill_soundchanneltablebody(vv) { $tablesizeSoundChannel.text("Table Size: " + vv.length); } - +/** + * Reload sound channels from server + * @param {String} APIURL API URL endpoint (default "SoundChannel/") + */ +function reloadSoundChannel(APIURL = "SoundChannel/") { + window.soundChannels = []; + fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + //console.log("reloadSoundChannel : ", okdata) + window.soundChannels.push(...okdata); + fill_soundchanneltablebody(window.soundChannels); + } else console.log("reloadSoundChannel: okdata is not array"); + }, (errdata) => { + alert("Error loading sound channels : " + errdata.message); + }); +} $(document).ready(function () { console.log("soundchannel.js loaded successfully"); @@ -83,15 +108,11 @@ $(document).ready(function () { $soundchannelip.val(''); } - reloadSoundChannel(API_SoundChannel, () => { - fill_soundchanneltablebody(window.soundChannels); - }); + reloadSoundChannel(API_SoundChannel); $btnReinitializeSoundChannel.click(() => { DoClear(API_SoundChannel, "SoundChannels", (okdata) => { - reloadSoundChannel(API_SoundChannel, () => { - fill_soundchanneltablebody(window.soundChannels); - alert("Success clear sound channels: " + okdata.message); - }); + reloadSoundChannel(API_SoundChannel); + alert("Success clear sound channels: " + okdata.message); }, (errdata) => { alert("Error clear sound channels: " + errdata.message); }); @@ -135,10 +156,8 @@ $(document).ready(function () { fetchAPI(API_SoundChannel + "UpdateByIndex/" + newsc.index, "PATCH", {}, newsc, (okdata) => { - reloadSoundChannel(API_SoundChannel, () => { - fill_soundchanneltablebody(window.soundChannels); - alert("Success edit sound channel: " + okdata.message); - }); + reloadSoundChannel(API_SoundChannel); + alert("Success edit sound channel: " + okdata.message); }, (errdata) => { alert("Error edit sound channel: " + errdata.message); }); @@ -158,10 +177,8 @@ $(document).ready(function () { $btnImportSoundChannel.click(() => { DoImport(API_SoundChannel, (okdata) => { - reloadSoundChannel(API_SoundChannel, () => { - fill_soundchanneltablebody(window.soundChannels); - alert("Success import sound channels: " + okdata.message); - }); + reloadSoundChannel(API_SoundChannel); + alert("Success import sound channels: " + okdata.message); }, (errdata) => { alert("Error importing sound channels from XLSX: " + errdata.message); }); diff --git a/html/webpage/assets/js/usermanagement.js b/html/webpage/assets/js/usermanagement.js index 5dc01b3..34c6a55 100644 --- a/html/webpage/assets/js/usermanagement.js +++ b/html/webpage/assets/js/usermanagement.js @@ -4,9 +4,10 @@ * @property {string} username Username * @property {string} password Password (plain) * @property {string} location Location - * @property {string} soundbank_tags Soundbank variable tags separated by semicolon ; - * @property {string} messagebank_ann_id Messagebank announcement ID separated by semicolon ; - * @property {string} broadcastzones Broadcast zones separated by semicolon ; + * @property {string} airline_tags Airline variable tags (string) separated by semicolon ; + * @property {string} city_tags City variable tags (string) separated by semicolon ; + * @property {string} messagebank_ann_id Messagebank announcement ID (number) separated by semicolon ; + * @property {string} broadcastzones Broadcast zones description (string) separated by semicolon ; */ /** List of UserDB data loaded from server @@ -20,13 +21,96 @@ window.userdb = []; */ window.selecteduserrow = null; +/** + * @typedef {Object} KeyValueMessage + * @property {string} key + * @property {string} value + */ + +/** + * List of airline tags loaded from server + * @type {KeyValueMessage[]} + */ +window.airlinetags = []; +/** + * List of city tags loaded from server + * @type {KeyValueMessage[]} + */ +window.citytags = []; +/** + * List of message bank IDs loaded from server + * @type {KeyValueMessage[]} + */ +window.messagebankids = []; +/** + * List of broadcast zones description loaded from server + * @type {string[]} + */ +window.broadcastzones = []; + +/** + * Get Messagebank ANN_IDs from server + */ +function get_messagebankids() { + messagebankids = []; + fetchAPI("MessageBank/" + "MessageIDs", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + messagebankids.push(...okdata); + } + }, (errdata) => { + alert("Error loading message bank IDs : " + errdata.message); + }); +} + +/** + * Get Airline Tags from server + */ +function get_airlinetags() { + airlinetags = []; + fetchAPI("SoundBank/" + "AirlineTags", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + airlinetags.push(...okdata); + } + }, (errdata) => { + alert("Error loading airline tags : " + errdata.message); + }); +} + +/** + * Get City Tags from server + */ +function get_citytags() { + citytags = []; + fetchAPI("SoundBank/" + "CityTags", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + citytags.push(...okdata); + } + }, (errdata) => { + alert("Error loading city tags : " + errdata.message); + }); +} + +/** + * Get Broadcast Zones descriptions from server + */ +function get_broadcastzones_descriptions() { + broadcastzones = []; + fetchAPI("BroadcastZones/" + "BroadcastZoneDescriptions", "GET", {}, null, (okdata) => { + if (Array.isArray(okdata)) { + broadcastzones.push(...okdata); + } + }, (errdata) => { + alert("Error loading broadcast zones : " + errdata.message); + }); +} + /** * Fill user table body with values * @param {UserDB[]} vv values to fill */ function fill_usertablebody(vv) { $('#usertablebody').empty(); - + if (!Array.isArray(vv) || vv.length === 0) { $('#btnExport').prop('disabled', true); return; @@ -34,10 +118,12 @@ function fill_usertablebody(vv) { vv.forEach(item => { const row = ` ${item.index} - ${item.datenya} - ${item.timenya} - ${item.machine} - ${item.description} + ${item.username} + ${item.location} + ${item.airline_tags} + ${item.city_tags} + ${item.messagebank_ann_id} + ${item.broadcastzones} `; $('#usertablebody').append(row); let $addedrow = $('#usertablebody tr:last'); @@ -63,9 +149,9 @@ function fill_usertablebody(vv) { /** * Reload UserDB from server with date and filter - * @param {String} APIURL API URL endpoint , default "User/" + * @param {String} APIURL API URL endpoint , default "UserManagement/" */ -function reloaduserDB(APIURL = "User/") { +function reloaduserDB(APIURL = "UserManagement/") { window.userdb = []; fetchAPI(APIURL + "List", "GET", {}, null, (okdata) => { if (Array.isArray(okdata)) { @@ -79,6 +165,12 @@ function reloaduserDB(APIURL = "User/") { $(document).ready(function () { console.log("usermanagement.js ready"); + get_airlinetags(); + get_citytags(); + get_messagebankids(); + get_broadcastzones_descriptions(); + + let $usertablebody = $('#usertablebody'); let $finduser = $('#finduser'); let $btnClear = $('#btnClear'); @@ -87,7 +179,7 @@ $(document).ready(function () { let $btnEdit = $('#btnEdit'); let $btnExport = $('#btnExport'); let $btnImport = $('#btnImport'); - let APIURL = "User/"; + let APIURL = "UserManagement/"; // add / edit modal elements let $addmodal = $('#addmodal'); @@ -95,34 +187,407 @@ $(document).ready(function () { let $modalusername = $('#modalusername'); let $modalpassword = $('#modalpassword'); let $modalverifypassword = $('#modalverifypassword'); - let $modalsoundbank = $('#modalsoundbank'); + let $modallocation = $('#modallocation'); + let $modalairlinetags = $('#modalairlinetags'); + let $modalcitytags = $('#modalcitytags'); let $modalmessagebank = $('#modalmessagebank'); let $modalbroadcastzones = $('#modalbroadcastzones'); let $btnShowSoundbankModal = $('#btnShowSoundbankModal'); let $btnShowMessagebankModal = $('#btnShowMessagebankModal'); let $btnShowBroaadcastZoneModal = $('#btnShowBroaadcastZoneModal'); - let $usermanagementsave = $('#usermanagementsave'); - let $usermanagementclose = $('#usermanagementclose'); - + + + function clearAddModal() { + $modalindex.val(""); + $modalusername.val(""); + $modalpassword.val(""); + $modalverifypassword.val(""); + $modalairlinetags.val(""); + $modalcitytags.val(""); + $modalmessagebank.val(""); + $modalbroadcastzones.val(""); + $modallocation.val(""); + } + // soundbank selection modal elements let $soundbankmodal = $('#soundbankmodal'); - let $soundbankselection = $('#soundbankselection'); - let $soundbankselectionsave = $('#soundbankselectionsave'); - let $soundbankselectionclose = $('#soundbankselectionclose'); - + let $citylist = $('#citylist'); + let $airlinelist = $('#airlinelist'); + + function fill_citylist() { + $citylist.empty(); + citytags.forEach(tag => { + let value = `${tag.value} [${tag.key}]`; + const row = `
+ + +
`; + $citylist.append(row); + }); + } + + function fill_airlinelist() { + $airlinelist.empty(); + airlinetags.forEach(tag => { + let value = `${tag.value} [${tag.key}]`; + const row = `
+ + +
`; + $airlinelist.append(row); + }); + } + // broadcast zone selection modal elements let $broadcastzonemodal = $('#broadcastzonemodal'); - let $broadcastzoneselection = $('#broadcastzoneselection'); - let $broadcastzoneselectionsave = $('#broadcastzoneselectionsave'); - let $broadcastzoneselectionclose = $('#broadcastzoneselectionclose'); - + let $broadcastzonelist = $('#broadcastzonelist'); + + function fill_broadcastzonelist() { + $broadcastzonelist.empty(); + broadcastzones.forEach(desc => { + const row = `
+ + +
`; + $broadcastzonelist.append(row); + }); + } + + // messagebank selection modal elements let $messagebankmodal = $('#messagebankmodal'); - let $messagebankselection = $('#messagebankselection'); - let $messagebankselectionsave = $('#messagebankselectionsave'); - let $messagebankselectionclose = $('#messagebankselectionclose'); + let $messagebanklist = $('#messagebanklist'); + + function fill_messagebanklist() { + $messagebanklist.empty(); + messagebankids.forEach(id => { + let value = `${id.value} [${id.key}]`; + const row = `
+ + +
`; + $messagebanklist.append(row); + }); + } + $usertablebody.empty(); + reloaduserDB(); $finduser.on('input', function () { + let searchTerm = $(this).val().toLowerCase(); + if (searchTerm.length > 0) { + let filteredUsers = window.userdb.filter(user => + user.username.toLowerCase().includes(searchTerm) || + user.airline_tags.toLowerCase().includes(searchTerm) || + user.city_tags.toLowerCase().includes(searchTerm) + //user.messagebank_ann_id.toLowerCase().includes(searchTerm) || + //user.broadcastzones.toLowerCase().includes(searchTerm) + ); + fill_usertablebody(filteredUsers); + } else { + fill_usertablebody(window.userdb); + } + + }); + + /** + * Show modal dialog for soundbank, messagebank, broadcastzone selection + * @param {boolean} editmode if true, edit mode, else add mode + * @param {number} index index of user to edit, default 0 + */ + function modalshow(editmode = false, index=0) { + // event on click btnShowSoundbankModal + $btnShowSoundbankModal.on('click', function () { + $soundbankmodal.modal('show'); + fill_citylist(); + fill_airlinelist(); + + let airline = $modalairlinetags.val().trim(); + let city = $modalcitytags.val().trim(); + if (airline.length > 0) { + let airlinekeys = airline.split(";"); + $('#airlinelist input[type=checkbox]').each(function () { + let tag = $(this).val(); + if (airlinekeys.includes(tag)) { + $(this).prop('checked', true); + } + }); + } + if (city.length > 0) { + let citykeys = city.split(";"); + $('#citylist input[type=checkbox]').each(function () { + let tag = $(this).val(); + if (citykeys.includes(tag)) { + $(this).prop('checked', true); + } + }); + } + + $soundbankmodal.on('click.soundbankselectionsave', '#soundbankselectionsave', function () { + let selected_airlinetags = []; + $('#airlinelist input[type=checkbox]:checked').each(function () { + selected_airlinetags.push($(this).val()); + }); + let selected_citytags = []; + $('#citylist input[type=checkbox]:checked').each(function () { + selected_citytags.push($(this).val()); + }); + + //console.log("Selected airline tags: ", selected_airlinetags); + //console.log("Selected city tags: ", selected_citytags); + + if (selected_airlinetags.length == 0 || selected_citytags.length == 0) { + alert("Please select at least one airline tag and one city tag."); + return; + } + + let airlinevalue = selected_airlinetags.join(";"); + let cityvalue = selected_citytags.join(";"); + $modalairlinetags.val(airlinevalue); + $modalcitytags.val(cityvalue); + + + $soundbankmodal.modal('hide'); + }); + $soundbankmodal.on('click.soundbankselectionclose', '#soundbankselectionclose', function () { + $soundbankmodal.modal('hide'); + }); + }); + // event on click btnShowMessagebankModal + $btnShowMessagebankModal.on('click', function () { + $messagebankmodal.modal('show'); + fill_messagebanklist(); + let messagebank = $modalmessagebank.val().trim(); + if (messagebank.length > 0) { + let messagebankkeys = messagebank.split(";"); + $('#messagebanklist input[type=checkbox]').each(function () { + let id = $(this).val(); + if (messagebankkeys.includes(id)) { + $(this).prop('checked', true); + } + }); + } + + $messagebankmodal.on('click.messagebankselectionsave', '#messagebankselectionsave', function () { + let selected_messagebankids = []; + $('#messagebanklist input[type=checkbox]:checked').each(function () { + selected_messagebankids.push($(this).val()); + }); + //console.log("Selected message bank IDs: ", selected_messagebankids); + if (selected_messagebankids.length == 0) { + alert("Please select at least one message bank ID."); + return; + } + let messagebankvalue = selected_messagebankids.join(";"); + $modalmessagebank.val(messagebankvalue); + + $messagebankmodal.modal('hide'); + }); + $messagebankmodal.on('click.messagebankselectionclose', '#messagebankselectionclose', function () { + $messagebankmodal.modal('hide'); + }); + }); + // event on click btnShowBroaadcastZoneModal + $btnShowBroaadcastZoneModal.on('click', function () { + $broadcastzonemodal.modal('show'); + fill_broadcastzonelist(); + let broadcastzones = $modalbroadcastzones.val().trim(); + if (broadcastzones.length > 0) { + let broadcastzonesvalues = broadcastzones.split(";"); + $('#broadcastzonelist input[type=checkbox]').each(function () { + let desc = $(this).val(); + if (broadcastzonesvalues.includes(desc)) { + $(this).prop('checked', true); + } + }); + } + $broadcastzonemodal.on('click.broadcastzoneselectionsave', '#broadcastzoneselectionsave', function () { + let selected_broadcastzones = []; + $('#broadcastzonelist input[type=checkbox]:checked').each(function () { + selected_broadcastzones.push($(this).val()); + }); + //console.log("Selected broadcast zones: ", selected_broadcastzones); + if (selected_broadcastzones.length == 0) { + alert("Please select at least one broadcast zone."); + return; + } + let broadcastzonesvalue = selected_broadcastzones.join(";"); + $modalbroadcastzones.val(broadcastzonesvalue); + $broadcastzonemodal.modal('hide'); + }); + $broadcastzonemodal.on('click.broadcastzoneselectionclose', '#broadcastzoneselectionclose', function () { + $broadcastzonemodal.modal('hide'); + }); + }); + + // event on Click save button + $addmodal.on('click.usermanagementsave', '#usermanagementsave', function () { + let username = $modalusername.val().trim(); + let password = $modalpassword.val(); + let verifypassword = $modalverifypassword.val(); + let location = $modallocation.val().trim(); + let airline_tags = $modalairlinetags.val().trim(); + let city_tags = $modalcitytags.val().trim(); + let messagebank_ann_id = $modalmessagebank.val().trim(); + let broadcastzones = $modalbroadcastzones.val().trim(); + + if (username.length === 0) { + alert("Username cannot be empty"); + return; + } + if (password.length === 0 || verifypassword.length === 0) { + alert("Password cannot be empty"); + return; + } + if (password !== verifypassword) { + alert("Password and Verify Password do not match"); + return; + } + if (airline_tags.length === 0) { + alert("Airline tags cannot be empty"); + return; + } + if (city_tags.length === 0) { + alert("City tags cannot be empty"); + return; + } + if (messagebank_ann_id.length === 0) { + alert("Message bank ANN_ID cannot be empty"); + return; + } + if (broadcastzones.length === 0) { + alert("Broadcast zones cannot be empty"); + return; + } + + /** + * @type {UserDB} + */ + let ll = { + index: index, + username: username, + password: password, + location: location, + airline_tags: airline_tags, + city_tags: city_tags, + messagebank_ann_id: messagebank_ann_id, + broadcastzones: broadcastzones + } + + if (editmode) { + fetchAPI(APIURL + "UpdateByIndex/" + index, "PATCH", {}, ll, (okdata) => { + alert("Success update User : " + okdata.message); + reloaduserDB(); + }, (errdata) => { + alert("Error update User : " + errdata.message); + }); + + } else { + fetchAPI(APIURL + "Add", "POST", {}, ll, (okdata) => { + alert("Success add User : " + okdata.message); + reloaduserDB(); + }, (errdata) => { + alert("Error add User : " + errdata.message); + }); + } + + + $addmodal.modal('hide'); + }); + // event on Click close button + $addmodal.on('click.usermanagementclose', '#usermanagementclose', function () { + $addmodal.modal('hide'); + }); + } + + $btnClear.on('click', function () { + DoClear(APIURL, "UserManagement", (okdata) => { + reloaduserDB(); + alert("Success clear user management : " + okdata.message); + }, (errdata) => { + alert("Error clear user management : " + errdata.message); + }); + }); + $btnAdd.click(() => { + $addmodal.modal('show'); + clearAddModal(); + modalshow(false,0); + }); + $btnRemove.click(() => { + if (window.selecteduserrow) { + let cells = window.selecteduserrow.find('td'); + /** @type {UserDB} */ + let user = { + index: parseInt(cells.eq(0).text()), + username: cells.eq(1).text(), + password: cells.eq(2).text(), + airline_tags: cells.eq(3).text(), + city_tags: cells.eq(4).text(), + messagebank_ann_id: cells.eq(5).text(), + broadcastzones: cells.eq(6).text() + } + if (confirm(`Are you sure to delete user [${user.index}] Username=${user.username} ?`)) { + fetchAPI(APIURL + "DeleteByIndex/" + user.index, "DELETE", {}, null, (okdata) => { + reloaduserDB(); + alert("Success delete user : " + okdata.message); + }, (errdata) => { + alert("Error delete user : " + errdata.message); + }); + } + } else { + alert("No user selected"); + } + }); + $btnEdit.click(() => { + if (window.selecteduserrow) { + let cells = window.selecteduserrow.find('td'); + let index = parseInt(cells.eq(0).text()); + if (isNaN(index) || index <= 0) { + alert("Invalid user index"); + return; + } + /** @type {UserDB} */ + let user = window.userdb.find(u => u.index === index); + if (!user) { + alert("User not found"); + return; + } + if (confirm(`Are you sure to edit user [${user.index}] Username=${user.username} ?`)) { + $addmodal.modal('show'); + // fill modal with user data + $modalindex.val(user.index); + $modalusername.val(user.username); + $modalpassword.val(user.password); + $modalverifypassword.val(user.password); + $modallocation.val(user.location); + $modalairlinetags.val(user.airline_tags); + $modalcitytags.val(user.city_tags); + $modalmessagebank.val(user.messagebank_ann_id); + $modalbroadcastzones.val(user.broadcastzones); + modalshow(true, user.index); + + } + } else { + alert("No user selected"); + } + }); + $btnExport.click(() => { + DoExport(APIURL, "user.xlsx", {}); + }); + $btnImport.click(() => { + DoImport(APIURL, (okdata) => { + reloaduserDB(); + alert("Success import user : " + okdata.message); + }, (errdata) => { + alert("Error importing user from XLSX : " + errdata.message); + }); }); }); \ No newline at end of file diff --git a/html/webpage/broadcastzones.html b/html/webpage/broadcastzones.html index 70f0bd3..a40cf17 100644 --- a/html/webpage/broadcastzones.html +++ b/html/webpage/broadcastzones.html @@ -4,8 +4,9 @@ - AAS_NewGen_30Sept25 + AAS_NewGen_08OKT25 + @@ -19,10 +20,10 @@