@@ -643,6 +795,10 @@ document.addEventListener("DOMContentLoaded", function() {
case "whitelabel":
loadWhitelabelSettings();
break;
+ case "license":
+ loadLicenseStatus();
+ loadLicenseUsage();
+ break;
case "developer":
loadSystemInfo();
loadErrorLogs();
@@ -820,6 +976,254 @@ function formatDate(dateStr) {
minute: "2-digit"
});
}
+
+// License Management Functions
+async function loadLicenseStatus() {
+ try {
+ const response = await fetch("api.php?action=license_status", {
+ headers: { "X-CSRF-Token": CSRF_TOKEN }
+ });
+ const data = await response.json();
+
+ if (!data.success) {
+ throw new Error(data.error || "Failed to load license status");
+ }
+
+ const container = document.getElementById("licenseStatusContainer");
+ const license = data.license;
+
+ let statusBadge = "";
+ let statusClass = "";
+
+ switch (license.status) {
+ case "active":
+ statusBadge = "Active";
+ statusClass = "badge-success";
+ break;
+ case "expired":
+ statusBadge = "Expired";
+ statusClass = "badge-error";
+ break;
+ case "inactive":
+ statusBadge = "Inactive";
+ statusClass = "badge-warning";
+ break;
+ case "unlicensed":
+ statusBadge = "Unlicensed";
+ statusClass = "badge-gray";
+ break;
+ default:
+ statusBadge = license.status;
+ statusClass = "badge-gray";
+ }
+
+ let expiryInfo = "";
+ if (license.expires_at) {
+ const expiryDate = new Date(license.expires_at);
+ expiryInfo = `
+ Expires: ${expiryDate.toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" })}
+ ${license.days_remaining !== null ? `(${license.days_remaining} days remaining)` : ""}
+
`;
+ }
+
+ let licenseDetails = "";
+ if (license.license && license.license.licensee_name) {
+ licenseDetails = `
+
+
Licensee: ${escapeHtml(license.license.licensee_name)}
+
Email: ${escapeHtml(license.license.licensee_email)}
+
License Key: ${maskLicenseKey(license.license.license_key)}
+
+ `;
+ // Show deactivate button
+ document.getElementById("deactivateLicenseBtn").style.display = "inline-flex";
+ } else {
+ document.getElementById("deactivateLicenseBtn").style.display = "none";
+ }
+
+ container.innerHTML = `
+
+ ${statusBadge}
+ ${license.limits?.name || "Unknown"} License
+
+
${license.message}
+ ${expiryInfo}
+ ${licenseDetails}
+ `;
+
+ } catch (error) {
+ console.error("Error loading license status:", error);
+ document.getElementById("licenseStatusContainer").innerHTML = `
+
+ Failed to load license status: ${escapeHtml(error.message)}
+
+ `;
+ }
+}
+
+function maskLicenseKey(key) {
+ if (!key || key.length < 10) return key;
+ return key.substring(0, 10) + "..." + key.substring(key.length - 4);
+}
+
+async function loadLicenseUsage() {
+ try {
+ const response = await fetch("api.php?action=license_usage", {
+ headers: { "X-CSRF-Token": CSRF_TOKEN }
+ });
+ const data = await response.json();
+
+ if (!data.success) {
+ throw new Error(data.error || "Failed to load license usage");
+ }
+
+ const container = document.getElementById("licenseUsageContainer");
+ const usage = data.usage;
+
+ const entriesBar = renderUsageBar(usage.entries);
+ const usersBar = renderUsageBar(usage.users);
+
+ container.innerHTML = `
+
+
+
+ Geofeed Entries
+
+ ${usage.entries.current} / ${usage.entries.unlimited ? "Unlimited" : usage.entries.max}
+
+
+ ${entriesBar}
+
+
+
+ Users
+
+ ${usage.users.current} / ${usage.users.unlimited ? "Unlimited" : usage.users.max}
+
+
+ ${usersBar}
+
+
+ `;
+
+ } catch (error) {
+ console.error("Error loading license usage:", error);
+ document.getElementById("licenseUsageContainer").innerHTML = `
+
+ Failed to load usage data: ${escapeHtml(error.message)}
+
+ `;
+ }
+}
+
+function renderUsageBar(usage) {
+ if (usage.unlimited) {
+ return `
`;
+ }
+
+ const percentage = Math.min(100, usage.percentage);
+ let barColor = "var(--purple-primary)";
+ if (percentage >= 90) {
+ barColor = "var(--error)";
+ } else if (percentage >= 75) {
+ barColor = "var(--warning)";
+ }
+
+ return `
+
+ `;
+}
+
+async function activateLicense() {
+ const licenseKey = document.getElementById("licenseKey").value.trim();
+ const licenseeName = document.getElementById("licenseeName").value.trim();
+ const licenseeEmail = document.getElementById("licenseeEmail").value.trim();
+
+ if (!licenseKey) {
+ showNotification("Please enter a license key", "error");
+ return;
+ }
+
+ if (!licenseeName) {
+ showNotification("Please enter the licensee name", "error");
+ return;
+ }
+
+ if (!licenseeEmail) {
+ showNotification("Please enter the licensee email", "error");
+ return;
+ }
+
+ try {
+ const response = await fetch("api.php?action=license_activate", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-CSRF-Token": CSRF_TOKEN
+ },
+ body: JSON.stringify({
+ license_key: licenseKey,
+ licensee_name: licenseeName,
+ licensee_email: licenseeEmail
+ })
+ });
+
+ const data = await response.json();
+
+ if (!data.success) {
+ throw new Error(data.error || "Failed to activate license");
+ }
+
+ showNotification(data.message || "License activated successfully", "success");
+
+ // Clear the form
+ document.getElementById("licenseKey").value = "";
+ document.getElementById("licenseeName").value = "";
+ document.getElementById("licenseeEmail").value = "";
+
+ // Reload license status
+ loadLicenseStatus();
+ loadLicenseUsage();
+
+ } catch (error) {
+ console.error("Error activating license:", error);
+ showNotification("Failed to activate license: " + error.message, "error");
+ }
+}
+
+async function deactivateLicense() {
+ if (!confirm("Are you sure you want to deactivate your license? This will revert your account to trial mode.")) {
+ return;
+ }
+
+ try {
+ const response = await fetch("api.php?action=license_deactivate", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-CSRF-Token": CSRF_TOKEN
+ }
+ });
+
+ const data = await response.json();
+
+ if (!data.success) {
+ throw new Error(data.error || "Failed to deactivate license");
+ }
+
+ showNotification(data.message || "License deactivated", "success");
+
+ // Reload license status
+ loadLicenseStatus();
+ loadLicenseUsage();
+
+ } catch (error) {
+ console.error("Error deactivating license:", error);
+ showNotification("Failed to deactivate license: " + error.message, "error");
+ }
+}
';
// Include footer