Merge branch 'development' into test

This commit is contained in:
“VeLiTi”
2026-02-05 10:14:22 +01:00
19 changed files with 229 additions and 45 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;