Files
AAS_NewGeneration/html/webpage/assets/js/schedulebank.js
2026-02-12 17:08:20 +07:00

634 lines
27 KiB
JavaScript

/**
* @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<HTMLElement>|null}
*/
window.selectedschedulerow = null;
dtScheduleBank = null;
dtTodaySchedule = null;
function fill_todayscheduletablebody(vv) {
dtTodaySchedule.clear();
if (!Array.isArray(vv) || vv.length === 0) return;
dtTodaySchedule.rows.add(vv);
dtTodaySchedule.draw();
}
/**
* Fill schedulebank table body with values
* @param {ScheduleBank[]} vv values to fill
*/
function fill_schedulebanktablebody(vv) {
dtScheduleBank.clear();
if (!Array.isArray(vv) || vv.length === 0) return;
dtScheduleBank.rows.add(vv);
dtScheduleBank.draw();
$('#schedulebanktable tbody').off('click').on('click', 'tr', function () {
// if no data
if (!dtScheduleBank) return;
// if user click an empty row
if (!dtScheduleBank.data().any()) return;
const selected = dtScheduleBank.row(this)
// toggle behaviour - unselect if already selected
if ($(this).hasClass('row-selected')) {
$(this).removeClass('row-selected').find('td').css('background-color', '');
window.selectedschedulerow = null;
$('#btnRemove').prop('disabled', true);
$('#btnEdit').prop('disabled', true);
return;
}
// unselect previously selected row
$('#schedulebanktable tbody tr.row-selected').removeClass('row-selected').find('td').css('background-color', '');
$(this).addClass('row-selected').find('td').css('background-color', '#ffeeba');
window.selectedschedulerow = selected.data();
$('#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);
});
}
function reloadTodaySchedule(APIURL = "ScheduleBank/") {
fetchAPI(APIURL + "TodaySchedule", "GET", {}, null, (okdata) => {
if (Array.isArray(okdata)) {
console.log("Today's Schedule: ", okdata);
fill_todayscheduletablebody(okdata);
}
}, (errdata) => {
alert("Error loading today's schedule : " + errdata.message);
});
}
dayViewMode = 'all'; // all, everyday, monday, tuesday, wednesday, thursday, friday, saturday, sunday
scheduledate = null; // Litepicker instance for schedule date selection
scheduletime = null; // time picker instance for schedule time selection
$schedulemodal = null; // schedule modal jQuery object
$(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/";
if (dtScheduleBank === null) {
dtScheduleBank = new DataTable('#schedulebanktable', {
dom: 'Bfrtip',
data: [],
pageLength: 25,
columns: [
{ title: "No", data: "index" },
{ title: "Description", data: "description" },
{ title: "Day", data: "day" },
{ title: "Time", data: "time" },
{ title: "Message", data: "soundpath" },
{ title: "Repeat", data: "repeat" },
{ title: "Enable", data: "enable" },
{ title: "Broadcast Zones", data: "broadcastZones" },
{ title: "Language", data: "language" }
],
buttons: ['print', 'pdf', {
extend: 'collection',
text: 'View',
className: 'btn btn-outline-secondary',
buttons: [
{text: 'All', className: 'btn btn-outline-primary', action() { dayViewMode = 'all'; dtScheduleBank.draw(); } },
{ text: 'Everyday', className: 'btn btn-outline-primary', action() { dayViewMode = 'everyday'; dtScheduleBank.draw(); } },
{ text: 'Monday', className: 'btn btn-outline-primary', action() { dayViewMode = 'monday'; dtScheduleBank.draw(); } },
{ text: 'Tuesday', className: 'btn btn-outline-primary', action() { dayViewMode = 'tuesday'; dtScheduleBank.draw(); } },
{ text: 'Wednesday', className: 'btn btn-outline-primary', action() { dayViewMode = 'wednesday'; dtScheduleBank.draw(); } },
{ text: 'Thursday', className: 'btn btn-outline-primary', action() { dayViewMode = 'thursday'; dtScheduleBank.draw(); } },
{ text: 'Friday', className: 'btn btn-outline-primary', action() { dayViewMode = 'friday'; dtScheduleBank.draw(); } },
{ text: 'Saturday', className: 'btn btn-outline-primary', action() { dayViewMode = 'saturday'; dtScheduleBank.draw(); } },
{ text: 'Sunday', className: 'btn btn-outline-primary', action() { dayViewMode = 'sunday'; dtScheduleBank.draw(); } },
{text: 'Special Date', className: 'btn btn-outline-primary', action() { dayViewMode = 'specialdate'; dtScheduleBank.draw(); } }
]
}]
});
}
if (dtTodaySchedule === null) {
dtTodaySchedule = new DataTable('#todaytable', {
dom: 'Bfrtip',
data: [],
pageLength: 25,
columns: [
{ title: "No", data: "index" },
{ title: "Description", data: "description" },
{ title: "Day", data: "day" },
{ title: "Time", data: "time" },
{ title: "Message", data: "soundpath" },
{ title: "Repeat", data: "repeat" },
{ title: "Enable", data: "enable" },
{ title: "Broadcast Zones", data: "broadcastZones" },
{ title: "Language", data: "language" }
],
buttons: ['print', 'pdf']
});
}
$.fn.dataTable.ext.search.push(function (settings, data, dataIndex, rowData) {
if (settings.nTable.id !== 'schedulebanktable') return true;
switch (dayViewMode) {
case 'everyday':
return rowData.day.toLowerCase() === 'everyday';
case 'monday':
return rowData.day.toLowerCase() === 'monday';
case 'tuesday':
return rowData.day.toLowerCase() === 'tuesday';
case 'wednesday':
return rowData.day.toLowerCase() === 'wednesday';
case 'thursday':
return rowData.day.toLowerCase() === 'thursday';
case 'friday':
return rowData.day.toLowerCase() === 'friday';
case 'saturday':
return rowData.day.toLowerCase() === 'saturday';
case 'sunday':
return rowData.day.toLowerCase() === 'sunday';
case 'specialdate':
// match dd/mm/yyyy format
return /^\d{2}\/\d{2}\/\d{4}$/.test(rowData.day);
default:
// 'all' include in here
return true;
}
})
$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');
scheduletime = flatpickr("#scheduletime",{
enableTime: true,
noCalendar: true, // time only
dateFormat: "H:i", // HH:mm format
time_24hr: true, // firce 24-hour format
minuteIncrement: 1,
defaultDate: new Date()
});
// 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');
scheduledate = new Litepicker({
element: document.getElementById('scheduledate'),
format: 'DD/MM/YYYY',
lang: 'en-US',
autoApply: true,
singleMode: true,
startDate: new Date(),
onSelect: (date) => {
console.log("Selected special date: " + date.format('DD/MM/YYYY'));
}
})
// 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);
scheduledate.disabled = false
} else {
//$scheduledate.prop('disabled', true);
scheduledate.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('');
scheduledate.disabled = true;
$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);
scheduledate.disabled = true;
}
});
$scheduleweekly.off('change').on('change', function () {
if ($(this).is(':checked')) {
$weeklyselect.prop('disabled', false);
//$scheduledate.prop('disabled', true);
scheduledate.disabled = true;
}
});
$schedulespecialdate.off('change').on('change', function () {
if ($(this).is(':checked')) {
$weeklyselect.prop('disabled', true);
//$scheduledate.prop('disabled', false);
scheduledate.disabled = false;
}
});
}
reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
reloadBroadcastZones();
getLanguages();
getScheduledDays();
reloadMessageBank();
$btnClear.click(() => {
DoClear(APIURL, "Timerbank", (okdata) => {
reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
alert("Success clear schedulebank : " + okdata.message);
}, (errdata) => {
alert("Error clear schedulebank : " + errdata.message);
});
});
$btnAdd.click(() => {
$schedulemodal.modal('show');
clearScheduleModal();
$scheduleeveryday.prop('checked', true).trigger('click');
$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.getDate().format('DD/MM/YYYY'));
} 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 = $('#scheduletime').val();
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
};
console.log("Adding schedule: ", scheduleObj);
fetchAPI(APIURL + "Add", "POST", {}, scheduleObj, (okdata) => {
reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
alert("Success add schedule: " + okdata.message);
}, (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) {
/** @type {ScheduleBank} */
let sr = {
index: window.selectedschedulerow.index,
description: window.selectedschedulerow.description,
day: window.selectedschedulerow.day,
time: window.selectedschedulerow.time,
soundpath: window.selectedschedulerow.soundpath,
repeat: window.selectedschedulerow.repeat,
enable: window.selectedschedulerow.enable,
broadcastZones: window.selectedschedulerow.broadcastZones,
language: window.selectedschedulerow.language
}
if (confirm(`Are you sure to delete schedule [${sr.index}] Description=${sr.description}?`)) {
fetchAPI(APIURL + "DeleteByIndex/" + sr.index, "DELETE", {}, null, (okdata) => {
reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
alert("Success delete schedule : " + okdata.message);
}, (errdata) => {
alert("Error delete schedule : " + errdata.message);
});
}
}
});
$btnEdit.click(() => {
if (window.selectedschedulerow) {
/** @type {ScheduleBank} */
let sr = {
index: window.selectedschedulerow.index,
Description: window.selectedschedulerow.description,
Day: window.selectedschedulerow.day,
Time: window.selectedschedulerow.time,
Soundpath: window.selectedschedulerow.soundpath,
Repeat: window.selectedschedulerow.repeat,
Enable: window.selectedschedulerow.enable,
BroadcastZones: window.selectedschedulerow.broadcastZones,
Language: window.selectedschedulerow.language
}
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());
scheduletime.setDate(sr.Time,true, "H:i");
$schedulemessage.val(sr.Soundpath).trigger('change');
$schedulerepeat.val(sr.Repeat);
$scheduleenable.prop('checked', sr.Enable);
$languageselect.val(sr.Language.split(';')).trigger('change');
$schedulezones.val(sr.BroadcastZones.split(';')).trigger('change');
switch (sr.Day) {
case 'Everyday':
// make the everyday radio button checked
$scheduleeveryday.prop('checked', true);
$weeklyselect.val(null).trigger('change');
$weeklyselect.prop('disabled', true);
//$scheduledate.prop('disabled', true);
scheduledate.disabled = true;
break;
case 'Sunday':
case 'Monday':
case 'Tuesday':
case 'Wednesday':
case 'Thursday':
case 'Friday':
case 'Saturday':
$scheduleweekly.prop('checked', true);
$weeklyselect.val(sr.Day).trigger('change');
$weeklyselect.prop('disabled', false);
//$scheduledate.prop('disabled', true);
scheduledate.disabled = true;
break;
default:
console.log("Assuming special date for Day: ", sr.Day);
// 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.prop('checked', true);
//$scheduledate.val(Convert_string_to_input_date(sr.Day));
// $scheduledate.prop('disabled', false);
scheduledate.setDate(dayjs(sr.Day,'DD/MM/YYYY'));
scheduledate.disabled = false;
$weeklyselect.val(null).trigger('change');
$weeklyselect.prop('disabled', true);
}
}
$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')) {
// convert date from yyyy-mm-dd to dd/mm/yyyy
//Day = Convert_input_date_to_string($scheduledate.val());
Day = scheduledate.getDate().format('DD/MM/YYYY');
} else if ($scheduleweekly.is(':checked')) {
Day = $weeklyselect.val();
}
// Broadcast zones (assuming comma-separated string)
const BroadcastZones = $schedulezones.val().join(';');
const Language = $languageselect.val().join(';');
// Format time as HH:mm
// const hour = parseInt($schedulehour.val(), 10);
//const minute = parseInt($scheduleminute.val(), 10);
const Time = $('#scheduletime').val();
if (Description && Description.length > 0) {
if (Day && Day.length > 0) {
if (Soundpath && Soundpath.length > 0) {
if (Time && Time.length > 0) {
if (Language && Language.length > 0) {
if (BroadcastZones && BroadcastZones.length > 0) {
// Prepare object
const scheduleObj = {
Description,
Day,
Time,
Soundpath,
Repeat,
Enable,
BroadcastZones,
Language
};
fetchAPI(APIURL + "UpdateByIndex/" + sr.index, "PATCH", {}, scheduleObj, (okdata) => {
alert("Success edit schedule: " + okdata.message);
reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
}, (errdata) => {
alert("Error edit schedule: " + errdata.message);
});
$schedulemodal.modal('hide');
} else alert("At least one Broadcast Zone is required");
} else alert("At least one Language is required");
} else alert("Time is invalid");
} else alert("Message is not selected");
} else alert("Day is invalid");
} else alert("Description is empty");
});
}
}
});
$btnExport.click(() => {
DoExport(APIURL, "schedulebank.xlsx", {});
});
$btnImport.click(() => {
DoImport(APIURL, (okdata) => {
reloadTimerBank(APIURL);
reloadTodaySchedule(APIURL);
alert("Success import schedulebank from XLSX : " + okdata.message);
}, (errdata) => {
alert("Error importing schedulebank from XLSX : " + errdata.message);
});
});
});