Enhance partner dropdowns to include authorization permissions across various management pages. Implement hardware version checks with warning modals for restricted versions. Update translations for hardware compatibility notices in multiple languages. Refactor SQL and PHP files to improve code clarity and maintainability.

This commit is contained in:
“VeLiTi”
2026-02-05 10:10:26 +01:00
parent 5223f6bdfd
commit ee426cf5ea
21 changed files with 235 additions and 51 deletions

View File

@@ -357,6 +357,7 @@ CREATE TABLE `user_roles` (
`updated` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`updatedby` varchar(255) DEFAULT NULL,
`is_system` tinyint(1) DEFAULT NULL,
`role_hierarchy` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`rowID`),
UNIQUE KEY `unique_role_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

View File

@@ -10,6 +10,51 @@ let deviceVersion = "";
let deviceHwVersion = "";
let selectedSoftwareUrl = "";
// Restricted hardware versions that require warning
const RESTRICTED_HW_VERSIONS = ['r06', 'r06a', 'r07', 'r07a', 'r07b'];
// Helper function to normalize hardware version for comparison
function normalizeHwVersion(hwVersion) {
if (!hwVersion) return '';
// Convert to lowercase and trim
let normalized = hwVersion.toLowerCase().trim();
// Remove leading zeros (e.g., "0000070" -> "70", "0000060" -> "60")
normalized = normalized.replace(/^0+/, '');
// If it starts with 'r', keep it as is (e.g., "r06a")
if (normalized.startsWith('r')) {
return normalized;
}
// Extract numeric part and suffix (e.g., "7a" -> "7" + "a", "70" -> "70" + "")
const match = normalized.match(/^(\d+)([a-z]*)$/);
if (!match) return 'r' + normalized; // Fallback
let numPart = match[1];
const suffix = match[2];
// Pad single digit to 2 digits (e.g., "7" -> "07", "6" -> "06")
if (numPart.length === 1) {
numPart = '0' + numPart;
} else if (numPart.length === 2 && numPart.endsWith('0') && numPart[0] !== '0') {
// "70" -> "07", "60" -> "06" (swap if needed)
numPart = '0' + numPart[0];
}
// Add 'r' prefix (e.g., "07" -> "r07", "07a" -> "r07a", "07b" -> "r07b")
return 'r' + numPart + suffix;
}
// Check if hardware version is restricted
function isRestrictedHardware(hwVersion) {
const normalized = normalizeHwVersion(hwVersion);
const isRestricted = RESTRICTED_HW_VERSIONS.includes(normalized);
console.log(`[HW Check] Original: "${hwVersion}" -> Normalized: "${normalized}" -> Restricted: ${isRestricted}`);
return isRestricted;
}
// Helper function to generate country select options
function generateCountryOptions(selectedCountry = '') {
if (typeof COUNTRIES === 'undefined' || !COUNTRIES) {
@@ -242,7 +287,7 @@ async function connectDeviceForSoftware() {
// TEST MODE: Use mock device data
deviceSerialNumber = "22110095";
deviceVersion = "03e615af";
deviceHwVersion = "0000080";
deviceHwVersion = "0000070";
document.getElementById("Device_output").style.display = "block";
serialResultsDiv.innerHTML = `<strong style="color: #ff9800;">DEBUG MODE - Simulated Device Data:</strong><br>SN=${deviceSerialNumber}<br>FW=${deviceVersion}<br>HW=${deviceHwVersion}`;
@@ -624,20 +669,30 @@ async function fetchSoftwareOptions() {
const customerDataShownThisSession = sessionStorage.getItem('customerDataShownThisSession');
// Show user info modal unless:
// 1. We're in debug mode
// 2. We're returning from payment
// 3. We already showed the modal in this session
if ((typeof DEBUG === 'undefined' || !DEBUG || typeof DEBUG_ID === 'undefined' || !DEBUG_ID)
&& !isReturningFromPayment
&& !customerDataShownThisSession) {
// 1. We're returning from payment
// 2. We already showed the modal in this session
if (!isReturningFromPayment && !customerDataShownThisSession) {
// Always show userInfoModal (even in debug mode)
showUserInfoModal();
} else {
// Debug mode, returning from payment, or already shown this session - reveal software options immediately
const softwareOptions = document.getElementById("softwareOptions");
if (softwareOptions) {
softwareOptions.style.filter = "none";
softwareOptions.style.opacity = "1";
softwareOptions.style.pointerEvents = "auto";
// Returning from payment or already shown this session
console.log('[HW Check] Skipping userInfoModal - checking hardware version...');
console.log('[HW Check] deviceHwVersion:', deviceHwVersion);
// Check if hardware version is restricted
if (isRestrictedHardware(deviceHwVersion)) {
// Show hardware warning modal
console.log('[HW Check] Hardware is restricted - showing warning modal');
showHwWarningModal();
} else {
// Reveal software options immediately
console.log('[HW Check] Hardware is not restricted - revealing options');
const softwareOptions = document.getElementById("softwareOptions");
if (softwareOptions) {
softwareOptions.style.filter = "none";
softwareOptions.style.opacity = "1";
softwareOptions.style.pointerEvents = "auto";
}
}
}
@@ -1014,12 +1069,18 @@ function showUserInfoModal() {
// Close modal
document.body.removeChild(modal);
// Reveal software options by removing blur
const softwareOptions = document.getElementById("softwareOptions");
if (softwareOptions) {
softwareOptions.style.filter = "none";
softwareOptions.style.opacity = "1";
softwareOptions.style.pointerEvents = "auto";
// Check if hardware version is restricted
if (isRestrictedHardware(deviceHwVersion)) {
// Show hardware warning modal
showHwWarningModal();
} else {
// Reveal software options by removing blur
const softwareOptions = document.getElementById("softwareOptions");
if (softwareOptions) {
softwareOptions.style.filter = "none";
softwareOptions.style.opacity = "1";
softwareOptions.style.pointerEvents = "auto";
}
}
};
}
@@ -1064,6 +1125,82 @@ async function sendUserInfoToAPI(customerData) {
}
}
function showHwWarningModal() {
console.log(`[HW Check] Showing hardware warning modal for HW version: ${deviceHwVersion}`);
// Create modal overlay - matching userInfoModal
const modal = document.createElement("div");
modal.id = "hwWarningModal";
modal.style.cssText = `
display: flex;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
z-index: 2000;
align-items: center;
justify-content: center;
`;
// Create modal content - matching userInfoModal
const modalContent = document.createElement("div");
modalContent.style.cssText = `
background: white;
border-radius: 12px;
max-width: 500px;
width: 90%;
max-height: 90vh;
overflow-y: auto;
margin: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.4);
`;
modalContent.innerHTML = `
<div style="padding: 30px; border-bottom: 2px solid #e0e0e0;">
<h3 style="margin: 0; color: #333; font-size: 24px;">${typeof TRANS_HW_WARNING_TITLE !== 'undefined' ? TRANS_HW_WARNING_TITLE : 'Hardware Compatibility Notice'}</h3>
<p style="margin: 10px 0 0 0; color: #666; font-size: 14px;">${typeof TRANS_HW_WARNING_SUBTITLE !== 'undefined' ? TRANS_HW_WARNING_SUBTITLE : 'Please read the following information carefully'}</p>
</div>
<div style="padding: 30px;">
<div style="margin-bottom: 20px; padding: 20px; background: #fff3cd; border-left: 4px solid #ff9800; border-radius: 4px;">
<div style="display: flex; align-items: flex-start; gap: 15px;">
<i class="fa-solid fa-exclamation-triangle" style="font-size: 32px; color: #ff9800; margin-top: 5px;"></i>
<div>
<p style="margin: 0 0 10px 0; color: #333; font-size: 14px; font-weight: 600;">
${typeof TRANS_HW_WARNING_DETECTED !== 'undefined' ? TRANS_HW_WARNING_DETECTED.replace('{hw_version}', deviceHwVersion) : `Hardware version ${deviceHwVersion} detected`}
</p>
<p style="margin: 0; color: #666; font-size: 14px; line-height: 1.6;">
${typeof TRANS_HW_WARNING_TEXT !== 'undefined' ? TRANS_HW_WARNING_TEXT : 'This hardware version requires special attention. Please ensure you select the correct software version for your device.'}
</p>
</div>
</div>
</div>
<button id="hwWarningContinue" style="width: 100%; padding: 15px; background: linear-gradient(135deg, #04AA6D 0%, #038f5a 100%); color: white; border: none; border-radius: 8px; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.3s;" onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 6px 16px rgba(4,170,109,0.3)'" onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='none'">
${typeof TRANS_CONTINUE !== 'undefined' ? TRANS_CONTINUE : 'Continue'}
</button>
</div>
`;
modal.appendChild(modalContent);
document.body.appendChild(modal);
// Handle continue button click
document.getElementById("hwWarningContinue").onclick = () => {
// Close modal
document.body.removeChild(modal);
// Reveal software options by removing blur
const softwareOptions = document.getElementById("softwareOptions");
if (softwareOptions) {
softwareOptions.style.filter = "none";
softwareOptions.style.opacity = "1";
softwareOptions.style.pointerEvents = "auto";
}
};
}
async function selectUpgrade(option) {
const price = parseFloat(option.price || 0);
const isFree = price === 0;