const ApiService = {
baseUrl: "[Link]
requestCache: {},
requestDebounce: {},
cacheTimeout: 2e3,
async request(t, e = "GET", s = null, i = !1) {
try {
const a = `${e}-${t}-${[Link](s || {})}`;
if (
"GET" === e &&
!i &&
[Link][a] &&
[Link]() - [Link][a].timestamp < [Link]
)
return [Link][a].data;
if (
[Link][a] &&
[Link]() - [Link][a] < 500
)
return "DEBOUNCED";
[Link][a] = [Link]();
const n = {
method: e,
headers: { "Content-Type": "application/x-www-form-urlencoded" },
};
s &&
([Link] = [Link](s)
.map((t) => encodeURIComponent(t) + "=" + encodeURIComponent(s[t]))
.join("&"));
const o = await fetch(`${[Link]}${t}`, n);
if (![Link]) throw new Error(`HTTP error ${[Link]}`);
const c = (await [Link]()).trim();
return (
"GET" === e &&
([Link][a] = { data: c, timestamp: [Link]() }),
c
);
} catch (t) {
return "FALSE";
}
},
clearCache(t = null) {
t
? [Link]([Link]).forEach((e) => {
[Link](t) && delete [Link][e];
})
: ([Link] = {});
},
async get(t) {
return await [Link](t, "GET");
},
async post(t, e, s = null) {
return s && [Link](s), await [Link](t, "POST", e);
},
getContacts() {
return [Link]("/contacts");
},
addContact(t) {
return [Link]("/contacts", t, "/contacts");
},
clearContacts() {
return [Link]("/contacts/clear", null, "/contacts");
},
saveDeviceCredentials(t) {
const e = `${[Link]},${[Link]},${[Link]}`;
return [Link]("/save-mqtt", { mqttData: e });
},
saveSSIDCredentials(t) {
const e = `${[Link]},${[Link]}`;
return [Link]("/save-ssid", { ssidData: e });
},
getNotificationSettings() {
return [Link]("/notification-settings");
},
saveNotificationSettings(t) {
return [Link]("/notification-settings", t);
},
testZone(t) {
return [Link](`/zone${t}-test`, null);
},
testEMCP(t) {
return [Link](`/emcp${t}-test`, null);
},
isolateZone(t) {
return [Link](`/zone${t}-isolate`, null);
},
systemReset() {
return [Link]("/system-reset", null);
},
getZoneStatuses() {
return [Link]("/zones-status");
},
getZoneStatus(t) {
return [Link](`/zone-status/${t}`);
},
updateZoneStatus(t, e) {
return [Link]("/zone-update", { zone: t, status: e });
},
getEventLogs() {
return [Link]("/event-logs-special");
},
addEventLog(t) {
if ("string" == typeof t && [Link]("->*"))
return [Link]("/event-log-special", { logEntry: t });
{
const e = `${[Link]},${[Link]},${[Link]},${[Link]},${[Link]}`;
return [Link]("/event-log", { logData: e });
}
},
getBatteryStatus() {
return [Link]("/battery-status");
},
updateBatteryStatus(t) {
return [Link]("/battery-update", t);
},
getTimeStatus() {
return [Link]("/time-status");
},
setTimeStatus(t) {
return [Link]("/set-time", { timeData: t });
},
getSirenStatus() {
return [Link]("/siren-status");
},
login(t) {
return [Link]("/login", t);
},
logout() {
return [Link]("/logout", null);
},
},
UIService = {
contacts: [],
init() {
[Link]();
},
showNotification(t, e = !0) {
if ("Battery status updated successfully" === t) return;
const s = [Link]("div");
([Link] = "notification " + (e ? "success" : "error")),
([Link] = `\n <i class="${
e ? "fas fa-check-circle" : "fas fa-exclamation-circle"
}"></i>\n <span>${t}</span>\n `),
[Link](s),
setTimeout(() => [Link]("show"), 10),
setTimeout(() => {
[Link]("show"), setTimeout(() => [Link](), 300);
}, 3e3);
},
async loadContacts() {
const t = await [Link]();
if ("FALSE" !== t) {
if ((([Link] = []), "TRUE" !== t)) {
[Link](";").forEach((t) => {
if ([Link]()) {
const [e, s, i] = [Link](",");
[Link]({ name: e, email: s, phone: i });
}
});
}
[Link]();
} else [Link]("Failed to load contacts", !1);
},
refreshContactsList() {
const t = [Link]("contact-list");
t &&
(([Link] = ""),
0 !== [Link]
? [Link]([Link](this))
: ([Link] =
'<li class="contact-item">No contacts added yet.</li>'));
},
addContactToList(t) {
const e = [Link]("contact-list");
if (!e) return;
const s = [Link]("li");
([Link] = "contact-item"),
([Link] = `\n <div class="contact-details">\n
<div><strong>Name:</strong> ${[Link]}</div>\n
<div><strong>Email:</strong> ${[Link]}</div>\n
<div><strong>Phone:</strong> ${[Link]}</div>\n </div>\n `),
[Link](s);
},
async clearContacts() {
if (!confirm("Are you sure you want to clear all contacts?")) return;
"TRUE" === (await [Link]())
? (([Link] = []),
[Link](),
[Link]("All contacts cleared successfully"))
: [Link]("Failed to clear contacts", !1);
},
async addNewContact(t) {
return "TRUE" === (await [Link](t))
? (await [Link](),
[Link]("Contact added successfully"),
!0)
: ([Link]("Failed to add contact", !1), !1);
},
initContactForm() {
const t = [Link]("contact-form");
t &&
[Link]("submit", async (e) => {
[Link]();
const s = {
name: [Link]("client-name").[Link](),
email: [Link]("client-email").[Link](),
phone: [Link]("client-phone").[Link](),
};
if (!isValidEmail([Link]))
return void [Link](
"Please enter a valid email address",
!1
);
if (!isValidPhone([Link]))
return void [Link](
"Please enter a valid phone number",
!1
);
(await [Link](s)) && [Link]();
});
},
async loadDeviceCredentials() {
const t = await [Link]();
if ("FALSE" !== t && "TRUE" !== t) {
const [e, s, i] = [Link](",");
([Link]("client-id").value = e || ""),
([Link]("username").value = s || ""),
([Link]("password").value = i || "");
} else
"FALSE" === t &&
[Link]("Failed to load MQTT credentials", !1);
},
async saveDeviceCredentials() {
const t = [Link]("client-id").[Link](),
e = [Link]("username").[Link](),
s = [Link]("password").value;
if ([Link] > 24 || [Link] > 24 || [Link] > 24)
return (
[Link](
"MQTT credentials must not exceed 24 characters",
!1
),
!1
);
if (!t || !e)
return (
[Link]("Client ID and Username cannot be empty", !1),
!1
);
const i = {
clientId: [Link](0, 24),
username: [Link](0, 24),
password: [Link](0, 24),
};
return "TRUE" === (await [Link](i))
? ([Link]("MQTT credentials saved successfully!"),
await [Link](),
!0)
: ([Link]("Failed to save MQTT credentials", !1), !1);
},
async loadSSIDCredentials() {
const t = await [Link]();
if ("FALSE" !== t && "TRUE" !== t) {
const [e, s] = [Link](",");
([Link]("ssid").value = e || ""),
([Link]("ssid-password").value = s || "");
} else
"FALSE" === t &&
[Link]("Failed to load SSID credentials", !1);
},
async saveSSIDCredentials() {
const t = [Link]("ssid").[Link](),
e = [Link]("ssid-password").value;
if ([Link] > 16 || [Link] > 16)
return (
[Link](
"SSID credentials must not exceed 16 characters",
!1
),
!1
);
if (!t) return [Link]("SSID cannot be empty", !1), !1;
const s = { ssid: [Link](0, 16), password: [Link](0, 16) };
return "TRUE" === (await [Link](s))
? ([Link]("SSID credentials saved successfully!"),
await [Link](),
!0)
: ([Link]("Failed to save SSID credentials", !1), !1);
},
toggleCredentialForms(t) {
const e = [Link]("mqtt-form-container"),
s = [Link]("ssid-form-container"),
i = [Link]("mqtt-toggle"),
a = [Link]("ssid-toggle");
e &&
s &&
i &&
a &&
("mqtt" === t
? ([Link]("active"),
[Link]("active"),
[Link]("active"),
[Link]("active"),
[Link]("client-id").value ||
[Link]())
: ([Link]("active"),
[Link]("active"),
[Link]("active"),
[Link]("active"),
[Link]("ssid").value ||
[Link]()));
},
async loadNotificationSettings() {
const t = await [Link]();
if ("FALSE" !== t && "TRUE" !== t) {
const e = [Link](",").map((t) => "1" === t);
document
.querySelectorAll('.notification-table input[type="checkbox"]')
.forEach((t, s) => {
[Link] = e[s] || !1;
});
} else
"FALSE" === t &&
[Link]("Failed to load notification settings", !1);
},
async saveNotificationSettings() {
const t = [Link](
'.notification-table input[type="checkbox"]'
),
e = [Link](t)
.map((t) => ([Link] ? "1" : "0"))
.join(",");
return "TRUE" ===
(await [Link]({ settings: e }))
? ([Link]("Notification settings saved successfully!"),
!0)
: ([Link]("Failed to save notification settings", !1),
!1);
},
async testZone(t) {
"TRUE" === (await [Link](t))
? ([Link](t, VALID_STATUSES.FIRE),
await [Link](t, "fire"),
await [Link](t),
[Link](`Zone ${t} test initiated`))
: [Link](`Failed to test zone ${t}`, !1);
},
async isolateZone(t) {
"TRUE" === (await [Link](t))
? ([Link](t, VALID_STATUSES.ISOLATE),
[Link](`Zone ${t} isolated`),
await [Link](t))
: [Link](`Failed to isolate zone ${t}`, !1);
},
async performEMCPTest(t) {
if ("TRUE" === (await [Link](t))) {
[Link](t, VALID_STATUSES.FIRE);
const e = [Link](`emcp-button-${t}`);
e &&
([Link]("active"), ([Link] = `EMCP ${t} (Active)`)),
await [Link](t, "fire"),
await [Link](t),
[Link](`EMCP ${t} Test initiated successfully`);
} else [Link](`Failed to initiate EMCP ${t} test`, !1);
},
async performSystemReset() {
if (!confirm("Are you sure you want to reset the system?")) return;
if ("TRUE" === (await [Link]())) {
for (let t = 1; t <= 4; t++) {
const e = [Link](`emcp-button-${t}`);
e && ([Link]("active"), ([Link] = `EMCP ${t}`)),
await [Link](t, "normal"),
await [Link](t);
}
[Link]("System", "System", "System reset initiated"),
[Link]("System reset initiated successfully");
} else [Link]("Failed to reset system", !1);
},
addEventLogEntry(t, e) {
if (.includes(e)) return;
const s = [Link](".log-table tbody");
if (!s) return;
const i = new Date(),
a = [Link]("en-GB"),
n = [Link]("en-US", {
hour12: !1,
hour: "2-digit",
minute: "2-digit",
}),
o = {
serialNo: [Link]("tr").length + 1,
date: a,
time: n,
zone: `Zone ${t}`,
status: e,
},
c = [Link]("tr");
([Link] = `\n <td data-label="Serial No.">${
[Link]
}</td>\n <td data-label="Date">${
[Link]
}</td>\n <td data-label="Time">${
[Link]
}</td>\n <td data-label="Zone">${
[Link]
}</td>\n <td data-label="Status" class="status-$
{[Link]()}">${e}</td>\n `),
[Link](c, [Link]),
[Link](o);
},
async saveEventLog(t) {
await [Link](t);
},
async loadEventLogs() {
[Link](!0, "event-log-table");
try {
const t = await [Link]();
"FALSE" !== t && "TRUE" !== t
? [Link](t)
: "FALSE" === t
? ([Link]("Failed to load event logs", !1),
[Link]([]))
: [Link]([]);
} catch (t) {
[Link]("Error loading event logs", !1),
[Link]([]);
} finally {
[Link](!1, "event-log-table");
}
},
processEventLogs(t) {
[Link] > 1e5 &&
[Link]("Processing large data set, please wait...", !0),
setTimeout(() => {
try {
const e = [];
if ([Link]("->*")) {
const s = [Link](/[;\n]/),
i = (t, a) => {
const n = [Link](t + a, [Link]);
for (let i = t; i < n; i++) {
const t = s[i].trim();
if (!t) continue;
const a = [Link](/\(([0-9]{2}\/[0-9]{2}\/[0-9]{2})\)/),
n = [Link](/\(([0-9]{2}:[0-9]{2}:[0-9]{2})\)/),
o = [Link](/\*([A-Z0-9]+)#/);
if (a && n && o) {
const t = a[1],
s = n[1],
i = o[1];
[Link](i) &&
[Link]({
serialNo: [Link] + 1,
date: t,
time: s,
status: i,
});
}
}
n < [Link]
? setTimeout(() => i(n, a), 0)
: [Link](e);
};
i(0, 100);
} else {
const s = [Link](";"),
i = (t, a) => {
const n = [Link](t + a, [Link]);
for (let i = t; i < n; i++) {
const t = s[i];
if (![Link]()) continue;
const a = [Link](",");
if ([Link] >= 5) {
const t = a[0].trim(),
s = a[1].trim(),
i = a[2].trim(),
n = a[3].trim(),
o = [Link](4).join(",").trim(),
c = [Link](/Zone (\d+)/);
let r = [Link](o, c ? c[1] : "");
[Link]({ serialNo: t, date: s, time: i, status: r });
}
}
n < [Link]
? setTimeout(() => i(n, a), 0)
: [Link](e);
};
i(0, 100);
}
} catch (t) {
[Link]("Error processing event logs", !1),
[Link]([]);
}
}, 50);
},
isValidStatusCode: (t) =>
new RegExp(
`^(${["ISOL", "FIRE", "SHORT", "OPEN", "NORM"].join("|")})0[1-4]$`
).test(t),
convertToStatusCode(t, e) {
let s = "";
if (!e || isNaN(parseInt(e)) || parseInt(e) < 1 || parseInt(e) > 4)
return [Link]();
const i = [Link](2, "0");
return (
(s = (t = [Link]()).includes("fire")
? "FIRE"
: [Link]("isolate") || [Link]("isol")
? "ISOL"
: [Link]("short")
? "SHORT"
: [Link]("open")
? "OPEN"
: [Link]("normal") || [Link]("norm")
? "NORM"
: [Link](0, 4).toUpperCase()),
`${s}${i}`
);
},
showLoadingIndicator(t, e) {
const s = [Link](e);
if (!s) return;
let i = [Link](".loading-indicator");
t
? i ||
((i = [Link]("div")),
([Link] = "loading-indicator"),
([Link] =
'\n <div class="spinner"></div>\n
<p>Loading data...</p>\n '),
[Link](i))
: i && [Link]();
},
renderEventLogs(t) {
const e = [Link](".log-table tbody");
if (!e) return;
if ((([Link] = ""), !t || 0 === [Link]))
return void ([Link] =
'<tr><td colspan="5" style="text-align: center;">No event logs
available</td></tr>');
[Link]((t, e) => parseInt([Link]) - parseInt([Link]));
const s = 100,
i = [Link]([Link] / s);
let a = 1;
if (i > 1) {
const n = [Link]("event-log-table");
let o = [Link]("log-pagination");
!o &&
n &&
((o = [Link]("div")),
([Link] = "log-pagination"),
([Link] = "pagination-controls"),
[Link]("afterend", o),
[Link](o, a, i, (n) => {
(a = n),
[Link](t, e, n, s),
[Link](o, n, i, (n) => {
(a = n),
[Link](t, e, n, s),
[Link](o, n, i, null);
});
}));
}
[Link](t, e, a, s);
},
renderLogPage(t, e, s, i) {
[Link] = "";
const a = (s - 1) * i,
n = [Link](a + i, [Link]),
o = [Link]();
for (let e = a; e < n; e++) {
const s = t[e],
i = [Link]("tr");
[
{ label: "Serial No.", content: [Link] },
{ label: "Date", content: [Link] },
{ label: "Time", content: [Link] },
{ label: "Status", content: [Link] },
].forEach((t) => {
const e = [Link]("td");
[Link]("data-label", [Link]),
([Link] = [Link]),
"Status" === [Link] && [Link]("data-status", [Link]),
[Link](e);
}),
[Link](i);
}
[Link](o);
},
updatePagination(t, e, s, i) {
if ((([Link] = ""), s <= 1)) return void ([Link] = "none");
[Link] = "flex";
const a = [Link]("button");
([Link] = "pagination-btn" + (1 === e ? " disabled" : "")),
([Link] = "« Prev"),
([Link] = 1 === e),
[Link]("click", () => {
e > 1 && i && i(e - 1);
}),
[Link](a);
const n = [Link]("span");
([Link] = "pagination-info"),
([Link] = `Page ${e} of ${s}`),
[Link](n);
const o = [Link]("button");
([Link] = "pagination-btn" + (e === s ? " disabled" : "")),
([Link] = "Next »"),
([Link] = e === s),
[Link]("click", () => {
e < s && i && i(e + 1);
}),
[Link](o);
},
async loadZoneStatus(t) {
const e = await [Link](t);
"FALSE" !== e && "DEBOUNCED" !== e && [Link](t, e);
},
updateZoneStatus: async (t, e) => await [Link](t, e),
async login(t, e) {
return (
"TRUE" === (await [Link]({ username: t, password: e })) ||
([Link]("Login failed", !1), !1)
);
},
async loadBatteryStatus() {
try {
const t = [Link](".btn-refresh i");
t && [Link]("fa-spin");
const e = await [Link]();
if ("FALSE" !== e && "TRUE" !== e) {
const [t, s] = [Link](","),
i = [Link](".battery-status .status-text"),
a = [Link](".battery-voltage .voltage-text"),
n = [Link](".battery-status .status-indicator i");
if (
(i && t && ([Link] = [Link](0).toUpperCase() + [Link](1)),
n &&
(([Link] =
"connected" === t
? "fas fa-plug"
: "charging" === t
? "fas fa-battery-half"
: "fas fa-battery-empty"),
"charging" === t
? (([Link] = "#f39c12"),
([Link] = "pulse 1.5s infinite"))
: "connected" === t
? (([Link] = "#27ae60"), ([Link] = "none"))
: (([Link] = "#e74c3c"), ([Link] = "none"))),
a && s)
) {
const t = parseFloat(s).toFixed(1);
([Link] = `${t}V`),
([Link] =
t >= 23 ? "#27ae60" : t >= 21 ? "#f39c12" : "#e74c3c");
}
}
} catch (t) {
[Link]("Failed to fetch battery status", !1);
} finally {
const t = [Link](".btn-refresh i");
t && [Link]("fa-spin");
}
},
async loadTimeStatus() {
const t = await [Link]();
if ("FALSE" !== t && "TRUE" !== t) {
const [e, s] = [Link](","),
i = [Link](".time-display .time-text"),
a = [Link](".time-display .date-text");
i && e && ([Link] = e), a && s && ([Link] = s);
} else
"FALSE" === t &&
[Link]("Failed to load time status", !1);
},
async saveTimeSettings() {
const t = [Link]("time-input"),
e = [Link]("date-input");
if (!t || !e)
return [Link]("Time input fields not found", !1), !1;
const s = [Link],
i = [Link];
if (!s || !i)
return [Link]("Please enter both time and date", !1), !1;
const a = s + ":00",
n = [Link]("-");
if (3 !== [Link])
return [Link]("Invalid date format", !1), !1;
const o = `${a},${`${n[2]}/${n[1]}/${n[0]}`}`;
return "TRUE" === (await [Link](o))
? ([Link]("Time settings saved successfully!"),
await [Link](),
!0)
: ([Link]("Failed to save time settings", !1), !1);
},
async loadSirenStatus() {
const t = await [Link]();
if ("FALSE" !== t && "TRUE" !== t && "DEBOUNCED" !== t) {
const e = "1" === t,
s = [Link](".siren-status .status-text"),
i = [Link](".siren-status .status-indicator");
s && ([Link] = e ? "Active" : "Off"),
i &&
(e
? ([Link]("active"), [Link]("inactive"))
: ([Link]("inactive"), [Link]("active")));
} else
"FALSE" === t &&
[Link]("Failed to load siren status", !1);
},
updateZoneUI(t, e) {
const s = [Link](`.zone-card[data-zone="${t}"]`);
if (!s) return;
[Link](
"status-normal",
"status-fire",
"status-isolate",
"status-short",
"status-open"
),
[Link](`status-${[Link]()}`);
const i = [Link](".status-text");
i && ([Link] = [Link](0).toUpperCase() + [Link](1));
const a = [Link](".status-indicator i");
if (a)
switch ((([Link] = ""), [Link]())) {
case "normal":
[Link] = "fas fa-check-circle";
break;
case "fire":
[Link] = "fas fa-fire";
break;
case "isolate":
[Link] = "fas fa-ban";
break;
case "short":
[Link] = "fas fa-bolt";
break;
case "open":
[Link] = "fas fa-exclamation-triangle";
break;
default:
[Link] = "fas fa-question-circle";
}
},
async refreshSystemStatus() {
[Link]("Refreshing system status..."),
await [Link]([
[Link](),
[Link](),
[Link](),
[Link](1),
[Link](2),
[Link](3),
[Link](4),
]),
[Link]("System status refreshed");
},
async loadZoneStatuses() {
const t = await [Link]();
if ("FALSE" !== t && "TRUE" !== t) {
[Link](";").forEach((t) => {
if ([Link]()) {
const [e, s] = [Link](",");
e && s && [Link](parseInt([Link]()), [Link]());
}
});
} else
"FALSE" === t &&
[Link]("Failed to load zone statuses", !1);
},
},
AuthService = {
async logout() {
"TRUE" === (await [Link]())
? ([Link] = "[Link]")
: [Link]("Failed to logout", !1);
},
};
function toggleSidebar() {
[Link](".sidebar")?.[Link]("open"),
[Link](".overlay")?.[Link]("active");
}
function isValidEmail(t) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t);
}
function isValidPhone(t) {
return /^\+?[\d\s-]{10,}$/.test(t);
}
function setupSystemTestButtons() {
for (let t = 1; t <= 4; t++) {
const e = [Link](`emcp-button-${t}`);
e && [Link]("click", () => [Link](t));
}
const t = [Link]("reset-button");
t && [Link]("click", () => [Link]());
const e = [Link]("refresh-logs-btn");
e && [Link]("click", () => [Link]());
}
function showTab(t) {
document
.querySelectorAll(".tab-section")
?.forEach((t) => [Link]("active"));
const e = [Link](t);
e && [Link]("active"),
document
.querySelectorAll(".sidebar button")
?.forEach((t) => [Link]("active"));
const s = [Link](
`.sidebar button[onclick="showTab('${t}')"]`
);
s && [Link]("active"), [Link] <= 768 && toggleSidebar();
}
function handleLogout() {
confirm("Are you sure you want to logout?") && [Link]();
}
const VALID_STATUSES = {
NORMAL: "Normal",
FIRE: "Fire",
ISOLATE: "Isolate",
OPEN: "Open",
SHORT: "Short",
};
[Link]("DOMContentLoaded", async () => {
try {
[Link](),
await [Link]([
[Link](),
[Link](),
[Link](),
[Link](1),
[Link](2),
[Link](3),
[Link](4),
[Link](),
[Link](),
[Link](),
[Link](),
[Link](),
]),
setupSystemTestButtons(),
showTab("indicator");
const t = [Link]("mqtt-form-container"),
e = [Link]("ssid-form-container"),
s = [Link]("mqtt-toggle"),
i = [Link]("ssid-toggle");
t &&
e &&
s &&
i &&
([Link]("active"),
[Link]("active"),
[Link]("active"),
[Link]("active"),
[Link]("click", () =>
[Link]("mqtt")
),
[Link]("click", () =>
[Link]("ssid")
)),
document
.getElementById("device-credential-form")
?.addEventListener("submit", async (t) => {
[Link](), await [Link]();
}),
document
.getElementById("ssid-credential-form")
?.addEventListener("submit", async (t) => {
[Link](), await [Link]();
}),
document
.getElementById("save-time-btn")
?.addEventListener("click", () => [Link]()),
document
.querySelector(".save-btn")
?.addEventListener("click", () => [Link]()),
document
.getElementById("emcp-button")
?.addEventListener("click", () => [Link]()),
document
.getElementById("reset-button")
?.addEventListener("click", () => [Link]()),
document
.querySelector(".overlay")
?.addEventListener("click", toggleSidebar);
} catch (t) {
[Link](
"Failed to initialize application. Please refresh the page.",
!1
);
}
});