/** * @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} */ window.selectedschedulerow = null; /** * Fill schedulebank table body with values * @param {ScheduleBank[]} vv values to fill */ function fill_schedulebanktablebody(vv) { $('#schedulebanktablebody').empty(); if (!Array.isArray(vv) || vv.length === 0) return; vv.forEach(item => { const row = ` ${item.index} ${item.description} ${item.day} ${item.time} ${item.soundpath} ${item.repeat} ${item.enable} ${item.broadcastZones} ${item.language} `; $('#schedulebanktablebody').append(row); let $addedrow = $('#schedulebanktablebody tr:last'); $addedrow.click(function () { if (selectedschedulerow) { selectedschedulerow.find('td').css('background-color', ''); if (selectedschedulerow.is($(this))) { selectedschedulerow = null; $('#btnRemove').prop('disabled', true); $('#btnEdit').prop('disabled', true); return; } } $addedrow.find('td').css('background-color', '#ffeeba'); selectedschedulerow = $addedrow; $('#btnRemove').prop('disabled', false); $('#btnEdit').prop('disabled', false); }); }); $('#tablesize').text("Table Size: " + vv.length); } /** * Convert input date string yyyy-mm-dd to dd/mm/yyyy * @param {String} value from input date, which is in format yyyy-mm-dd * @returns {String} converted date in format dd/mm/yyyy */ function Convert_input_date_to_string(value){ if (value && value.length>0 && value.includes('-')){ let parts = value.split('-'); if (parts.length === 3) { let year = parts[0]; let month = parts[1]; let day = parts[2]; return `${day}/${month}/${year}`; } } return ""; } /** * Convert string date dd/mm/yyyy to input date yyyy-mm-dd * @param {String} value string date in format dd/mm/yyyy * @returns {String} converted date in format yyyy-mm-dd */ function Convert_string_to_input_date(value){ if (value && value.length>0 && value.includes('/')){ let parts = value.split('/'); if (parts.length === 3) { let day = parts[0]; let month = parts[1]; let year = parts[2]; return `${year}-${month}-${day}`; } } return ""; } /** * 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"); $('#schedulebanktablebody').empty(); selectedschedulerow = null; let $btnClear = $('#btnClear'); let $btnAdd = $('#btnAdd'); let $btnEdit = $('#btnEdit'); let $btnRemove = $('#btnRemove'); let $btnExport = $('#btnExport'); let $btnImport = $('#btnImport'); $btnEdit.prop('disabled', true); $btnRemove.prop('disabled', true); let APIURL = "ScheduleBank/"; let $schedulemodal = $('#schedulemodal'); // text input let $scheduleid = $schedulemodal.find('#scheduleid'); // text input let $scheduledescription = $schedulemodal.find('#scheduledescription'); // number input 0-23 let $schedulehour = $schedulemodal.find('#schedulehour'); // number input 0-59 let $scheduleminute = $schedulemodal.find('#scheduleminute'); // select2 for message let $schedulemessage = $schedulemodal.find('#schedulemessage'); // number input 0-5 let $schedulerepeat = $schedulemodal.find('#schedulerepeat'); // checkbox let $scheduleenable = $schedulemodal.find('#scheduleenable'); // select2 for broadcastzones let $schedulezones = $schedulemodal.find('#schedulezones'); // radio button for everyday let $scheduleeveryday = $schedulemodal.find('#scheduleeveryday'); // radio button for weekly let $scheduleweekly = $schedulemodal.find('#scheduleweekly'); // select2 for weekly selection let $weeklyselect = $schedulemodal.find('#weeklyselect'); // radio button for specific date let $schedulespecialdate = $schedulemodal.find('#schedulespecialdate'); // date input let $scheduledate = $schedulemodal.find('#scheduledate'); // select2 for language let $languageselect = $schedulemodal.find('#languageselect'); $schedulespecialdate.off('change').on('change', function () { if ($(this).is(':checked')) { $scheduledate.prop('disabled', false); } else { $scheduledate.prop('disabled', true); } }); function clearScheduleModal() { $scheduleid.prop('disabled', true).val(''); $scheduledescription.val(''); $schedulehour.val('0'); $scheduleminute.val('0'); $schedulerepeat.val('1'); $scheduleenable.prop('checked', true); $scheduleeveryday.prop('checked', false); $scheduleweekly.prop('checked', false); $schedulespecialdate.prop('checked', false); $weeklyselect.empty().select2({ data: window.scheduledays.filter(day => day !== 'Everyday').map(day => ({ id: day, text: day })), placeholder: 'Select days of the week', multiple: false, width: '100%', dropdownParent: $('#schedulemodal') }); $languageselect.empty().select2({ data: window.languages.map(lang => ({ id: lang, text: lang })), placeholder: 'Select languages', multiple: true, width: '100%', dropdownParent: $('#schedulemodal') }); $scheduledate.prop('disabled', true).val(''); $schedulezones.empty().select2({ data: window.BroadcastZoneList.map(zone => ({ id: zone.description, text: zone.description })), placeholder: 'Select broadcast zones', multiple: true, width: '100%', dropdownParent: $('#schedulemodal') }); let messageData = [...new Set(window.messagebankdata.filter(mb => !mb.message_Detail.includes('[')).map(mb => `${mb.description} [${mb.aNN_ID}]`))]; $schedulemessage.empty().select2({ placeholder: 'Select message', multiple: false, width: '100%', dropdownParent: $('#schedulemodal'), data: messageData.map(mb => ({ id: mb, text: mb })) }); $scheduleeveryday.off('change').on('change', function () { if ($(this).is(':checked')) { $weeklyselect.prop('disabled', true); $scheduledate.prop('disabled', true); } }); $scheduleweekly.off('change').on('change', function () { if ($(this).is(':checked')) { $weeklyselect.prop('disabled', false); $scheduledate.prop('disabled', true); } else { $weeklyselect.prop('disabled', true); } }); $schedulespecialdate.off('change').on('change', function () { if ($(this).is(':checked')) { $weeklyselect.prop('disabled', true); $scheduledate.prop('disabled', false); } else { $scheduledate.prop('disabled', true); } }); } let $findschedule = $('#findschedule'); $findschedule.off('input').on('input', function () { let searchTerm = $findschedule.val().toLowerCase(); if (searchTerm.length > 0) { window.selectedschedulerow = null; let filtered = window.schedulebankdata.filter(item => item.description.toLowerCase().includes(searchTerm) || item.soundpath.toLowerCase().includes(searchTerm) || item.broadcastZones.toLowerCase().includes(searchTerm)); fill_schedulebanktablebody(filtered); } else { window.selectedschedulerow = null; fill_schedulebanktablebody(window.schedulebankdata); } }); reloadTimerBank(APIURL); reloadBroadcastZones(); getLanguages(); getScheduledDays(); reloadMessageBank(); $btnClear.click(() => { DoClear(APIURL, "Timerbank", (okdata) => { reloadTimerBank(APIURL); alert("Success clear schedulebank : " + okdata.message); }, (errdata) => { alert("Error clear schedulebank : " + errdata.message); }); }); $btnAdd.click(() => { $schedulemodal.modal('show'); clearScheduleModal(); $schedulemodal.off('click.scheduleclose').on('click.scheduleclose', '#scheduleclose', function () { $schedulemodal.modal('hide'); }); $schedulemodal.off('click.schedulesave').on('click.schedulesave', '#schedulesave', function () { // Gather form values const Description = $scheduledescription.val(); const Message = $schedulemessage.val(); const Repeat = parseInt($schedulerepeat.val(), 10); const Enable = $scheduleenable.is(':checked'); // Collect selected days let _Day = ""; if ($scheduleeveryday.is(':checked')) { _Day = "Everyday"; } else if ($schedulespecialdate.is(':checked')) { _Day = Convert_input_date_to_string($scheduledate.val()); } else if ($scheduleweekly.is(':checked')) { _Day = $weeklyselect.val(); } const Language = $languageselect.val().join(';'); const broadcastZones = $schedulezones.val().join(';'); // Format time as HH:mm const hour = parseInt($schedulehour.val(), 10); const minute = parseInt($scheduleminute.val(), 10); const _Time = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`; console.log(`Adding schedule: Description=${Description}, Day=${_Day}, Time=${_Time}, Message=${Message}, Repeat=${Repeat}, Enable=${Enable}, BroadcastZones=${broadcastZones}, Language=${Language}`); if (Description.length > 0) { if (_Day.length > 0) { if (Message.length > 0) { if (Language.length > 0) { if (broadcastZones.length > 0) { // Prepare object const scheduleObj = { Description: Description, Day: _Day, Time: _Time, Soundpath: Message, Repeat: Repeat, Enable: Enable, BroadcastZones: broadcastZones, Language: Language }; fetchAPI(APIURL + "Add", "POST", {}, scheduleObj, (okdata) => { alert("Success add schedule: " + okdata.message); reloadTimerBank(APIURL); }, (errdata) => { alert("Error add schedule: " + errdata.message); }); $schedulemodal.modal('hide'); } else alert("At least one Broadcast Zone is required"); } else alert("Language is required"); } else alert("Message is required"); } else alert("Day is required"); } else alert("Description is required"); }); }); $btnRemove.click(() => { if (window.selectedschedulerow) { let cells = window.selectedschedulerow.find('td'); /** @type {ScheduleBank} */ let sr = { index: Number(cells.eq(0).text()), description: cells.eq(1).text(), day: cells.eq(2).text(), time: cells.eq(3).text(), soundpath: cells.eq(4).text(), repeat: cells.eq(5).text(), enable: cells.eq(6).text(), broadcastZones: cells.eq(7).text(), language: cells.eq(8).text() } if (confirm(`Are you sure to delete schedule [${sr.index}] Description=${sr.description}?`)) { fetchAPI(APIURL + "DeleteByIndex/" + sr.index, "DELETE", {}, null, (okdata) => { reloadTimerBank(APIURL); alert("Success delete schedule : " + okdata.message); }, (errdata) => { alert("Error delete schedule : " + errdata.message); }); } } }); $btnEdit.click(() => { if (window.selectedschedulerow) { let cells = window.selectedschedulerow.find('td'); /** @type {ScheduleBank} */ let sr = { index: Number(cells.eq(0).text()), Description: cells.eq(1).text(), Day: cells.eq(2).text(), Time: cells.eq(3).text(), Soundpath: cells.eq(4).text(), Repeat: cells.eq(5).text(), Enable: cells.eq(6).text(), BroadcastZones: cells.eq(7).text(), Language: cells.eq(8).text() } console.log('Editing schedule:', sr); if (confirm(`Are you sure to edit schedule [${sr.index}] Description=${sr.Description}?`)) { $schedulemodal.modal('show'); clearScheduleModal(); // fill the form with existing data $scheduleid.val(sr.index); $scheduledescription.val(sr.Description); let [hour, minute] = sr.Time.split(':').map(num => parseInt(num, 10)); $schedulehour.val(hour.toString()); $scheduleminute.val(minute.toString()); $schedulemessage.val(sr.Soundpath).trigger('change'); $schedulerepeat.val(sr.Repeat); $scheduleenable.prop('checked', sr.Enable.toLowerCase() === 'true'); $languageselect.val(sr.Language.split(';')).trigger('change'); $schedulezones.val(sr.BroadcastZones.split(';')).trigger('change'); switch (sr.Day) { case 'Everyday': $scheduleeveryday.click(); break; case 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday': console.log(`Setting weekly schedule for day: ${sr.Day}`); $scheduleweekly.click(); $weeklyselect.val(sr.Day).trigger('change'); break; default: // check if the day is in format dd/mm/yyyy // and set the special date radio button and date input if (/^\d{2}\/\d{2}\/\d{4}$/.test(sr.Day)) { $schedulespecialdate.click(); $scheduledate.val(Convert_string_to_input_date(sr.Day)); } } $schedulemodal.off('click.scheduleclose').on('click.scheduleclose', '#scheduleclose', function () { $schedulemodal.modal('hide'); }); $schedulemodal.off('click.schedulesave').on('click.schedulesave', '#schedulesave', function () { // Gather form values const Description = $scheduledescription.val(); const Soundpath = $schedulemessage.val(); const Repeat = parseInt($schedulerepeat.val(), 10); const Enable = $scheduleenable.is(':checked'); // Collect selected days let Day = ""; if ($scheduleeveryday.is(':checked')) { Day = "Everyday"; } else if ($schedulespecialdate.is(':checked')) { Day = $scheduledate.val(); } else { if ($schedulesunday.is(':checked')) Day = "Sunday"; if ($schedulemonday.is(':checked')) Day = "Monday"; if ($scheduletuesday.is(':checked')) Day = "Tuesday"; if ($schedulewednesday.is(':checked')) Day = "Wednesday"; if ($schedulethursday.is(':checked')) Day = "Thursday"; if ($schedulefriday.is(':checked')) Day = "Friday"; if ($schedulesaturday.is(':checked')) Day = "Saturday"; } // Broadcast zones (assuming comma-separated string) const BroadcastZones = $schedulezones.val(); // Validate required fields if (!Description || !Soundpath || Day === "") { alert("Description, sound path, and day are required."); return; } // Format time as HH:mm const hour = parseInt($schedulehour.val(), 10); const minute = parseInt($scheduleminute.val(), 10); const Time = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`; // Prepare object const scheduleObj = { Description, Day, Time, Soundpath, Repeat, Enable, BroadcastZones }; fetchAPI(APIURL + "UpdateByIndex/" + sr.index, "PATCH", {}, scheduleObj, (okdata) => { alert("Success edit schedule: " + okdata.message); reloadTimerBank(APIURL); }, (errdata) => { alert("Error edit schedule: " + errdata.message); }); $schedulemodal.modal('hide'); }); } } }); $btnExport.click(() => { DoExport(APIURL, "schedulebank.xlsx", {}); }); $btnImport.click(() => { DoImport(APIURL, (okdata) => { reloadTimerBank(APIURL); alert("Success import schedulebank from XLSX : " + okdata.message); }, (errdata) => { alert("Error importing schedulebank from XLSX : " + errdata.message); }); }); });