- Updated authorization checks in product management, product attributes, configurations, software, and user management files to use 'permissions' for consistency. - Ensured that all relevant pages correctly check user permissions for read, update, delete, and create actions. - Adjusted session variable references to align with the new permissions structure across various modules.
485 lines
23 KiB
PHP
485 lines
23 KiB
PHP
<?php
|
|
defined(page_security_key) or exit;
|
|
|
|
if (debug && debug_id == $_SESSION['authorization']['id']){
|
|
ini_set('display_errors', '1');
|
|
ini_set('display_startup_errors', '1');
|
|
error_reporting(E_ALL);
|
|
}
|
|
|
|
$page = 'softwaretool';
|
|
//Check if allowed
|
|
if (isAllowed($page,$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'R') === 0){
|
|
header('location: index.php');
|
|
exit;
|
|
}
|
|
$bearertoken = createCommunicationToken($_SESSION['authorization']['userkey']);
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// PAYMENT RETURN DETECTION
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
$payment_return = isset($_GET['order_id']) ? $_GET['order_id'] : null;
|
|
$payment_return_status = isset($_GET['payment_return']) ? $_GET['payment_return'] : null;
|
|
$paypal_token = isset($_GET['token']) ? $_GET['token'] : null; // PayPal returns with ?token=
|
|
|
|
// Handle payment cancellation - mark order as cancelled
|
|
if ($payment_return && $payment_return_status === 'cancelled') {
|
|
try {
|
|
$pdo = dbConnect($dbname);
|
|
$sql = 'UPDATE transactions SET payment_status = 999 WHERE txn_id = ?';
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute([$payment_return]);
|
|
|
|
if (debug) {
|
|
debuglog("Payment cancelled - Order ID: {$payment_return} marked as cancelled (999)");
|
|
}
|
|
} catch (Exception $e) {
|
|
if (debug) {
|
|
debuglog("Error marking order as cancelled: " . $e->getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle PayPal return - capture the order directly
|
|
if ($paypal_token && $payment_return) {
|
|
try {
|
|
// Get PayPal access token
|
|
$ch = curl_init(PAYPAL_URL . '/v1/oauth2/token');
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, 'grant_type=client_credentials');
|
|
curl_setopt($ch, CURLOPT_USERPWD, PAYPAL_CLIENT_ID . ':' . PAYPAL_CLIENT_SECRET);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
|
|
$response = curl_exec($ch);
|
|
curl_close($ch);
|
|
$token_data = json_decode($response, true);
|
|
$access_token = $token_data['access_token'] ?? '';
|
|
|
|
if ($access_token) {
|
|
// Capture the PayPal order
|
|
$capture_url = PAYPAL_URL . "/v2/checkout/orders/{$paypal_token}/capture";
|
|
$ch = curl_init($capture_url);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
'Content-Type: application/json',
|
|
'Authorization: Bearer ' . $access_token
|
|
]);
|
|
$response = curl_exec($ch);
|
|
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
if (debug) {
|
|
debuglog("PayPal Capture: HTTP $http_code - $response");
|
|
}
|
|
|
|
// Update transaction status based on capture result
|
|
if ($http_code == 200 || $http_code == 201) {
|
|
$capture_result = json_decode($response, true);
|
|
$capture_status = $capture_result['status'] ?? '';
|
|
|
|
$payment_status = null;
|
|
if ($capture_status === 'COMPLETED') {
|
|
$payment_status = 1; // Paid
|
|
} elseif ($capture_status === 'PENDING') {
|
|
$payment_status = 101; // Pending
|
|
}
|
|
|
|
if ($payment_status !== null) {
|
|
$pdo = dbConnect($dbname);
|
|
$sql = 'UPDATE transactions SET payment_status = ? WHERE txn_id = ?';
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute([$payment_status, $payment_return]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Redirect to clean URL
|
|
header("Location: ?page=softwaretool&payment_return=1&order_id={$payment_return}");
|
|
exit;
|
|
|
|
} catch (Exception $e) {
|
|
if (debug) {
|
|
debuglog("PayPal Capture Error: " . $e->getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
template_header('Softwaretool', 'softwaretool','view');
|
|
|
|
// Show payment return message if returning from payment
|
|
$view = '';
|
|
$payment_modal = '';
|
|
if ($payment_return && $payment_return_status) {
|
|
// Check actual payment status in database
|
|
$pdo = dbConnect($dbname);
|
|
$sql = 'SELECT payment_status FROM transactions WHERE txn_id = ?';
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute([$payment_return]);
|
|
$transaction = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($transaction) {
|
|
if ($transaction['payment_status'] == 1) {
|
|
// Payment confirmed as paid
|
|
$payment_modal = '
|
|
<div id="paymentModal" class="modal" style="display: flex; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center;">
|
|
<div class="modal-content" style="background: white; border-radius: 12px; max-width: 500px; margin: 20px; box-shadow: 0 10px 40px rgba(0,0,0,0.3); position: relative;">
|
|
<span class="close" onclick="closePaymentModal()" style="position: absolute; top: 15px; right: 20px; font-size: 28px; font-weight: bold; color: #999; cursor: pointer;">×</span>
|
|
<div style="text-align: center; padding: 40px 30px;">
|
|
<i class="fa-solid fa-check-circle" style="font-size: 64px; color: #28a745; margin-bottom: 20px;"></i>
|
|
<h2 style="color: #155724; margin-bottom: 15px;">Payment Successful!</h2>
|
|
<p style="margin-bottom: 10px; color: #333;">Your payment has been processed. Please reconnect your device to apply the software upgrade.</p>
|
|
<p style="font-size: 12px; color: #666; margin-bottom: 25px;">Order ID: '.htmlspecialchars($payment_return).'</p>
|
|
<button onclick="closePaymentModal()" class="btn" style="padding: 12px 30px;">Continue</button>
|
|
</div>
|
|
</div>
|
|
</div>';
|
|
} else if ($transaction['payment_status'] == 0 || $transaction['payment_status'] == 101) {
|
|
// Payment pending
|
|
$payment_modal = '
|
|
<div id="paymentModal" class="modal" style="display: flex; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center;">
|
|
<div class="modal-content" style="background: white; border-radius: 12px; max-width: 500px; margin: 20px; box-shadow: 0 10px 40px rgba(0,0,0,0.3);">
|
|
<div style="text-align: center; padding: 40px 30px;">
|
|
<i class="fa-solid fa-clock" style="font-size: 64px; color: #ffc107; margin-bottom: 20px;"></i>
|
|
<h2 style="color: #856404; margin-bottom: 15px;">Payment Processing...</h2>
|
|
<p style="margin-bottom: 10px; color: #333;">Your payment is being processed. This page will update automatically when confirmed.</p>
|
|
<p style="font-size: 12px; color: #666; margin-bottom: 25px;">Order ID: '.htmlspecialchars($payment_return).'</p>
|
|
<i class="fa-solid fa-spinner fa-spin" style="font-size: 32px; color: #ffc107;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
// Auto-refresh every 3 seconds to check payment status
|
|
setTimeout(function() { location.reload(); }, 3000);
|
|
</script>';
|
|
} else if ($transaction['payment_status'] == 999) {
|
|
// Payment cancelled
|
|
$payment_modal = '
|
|
<div id="paymentModal" class="modal" style="display: flex; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center;">
|
|
<div class="modal-content" style="background: white; border-radius: 12px; max-width: 500px; margin: 20px; box-shadow: 0 10px 40px rgba(0,0,0,0.3); position: relative;">
|
|
<span class="close" onclick="closePaymentModal()" style="position: absolute; top: 15px; right: 20px; font-size: 28px; font-weight: bold; color: #999; cursor: pointer;">×</span>
|
|
<div style="text-align: center; padding: 40px 30px;">
|
|
<i class="fa-solid fa-times-circle" style="font-size: 64px; color: #ffc107; margin-bottom: 20px;"></i>
|
|
<h2 style="color: #856404; margin-bottom: 15px;">Payment Cancelled</h2>
|
|
<p style="margin-bottom: 10px; color: #333;">You cancelled the payment. The order has been cancelled.</p>
|
|
<p style="font-size: 12px; color: #666; margin-bottom: 25px;">Order ID: '.htmlspecialchars($payment_return).'</p>
|
|
<button onclick="closePaymentModal()" class="btn" style="padding: 12px 30px;">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>';
|
|
} else {
|
|
// Payment failed/expired
|
|
$payment_modal = '
|
|
<div id="paymentModal" class="modal" style="display: flex; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center;">
|
|
<div class="modal-content" style="background: white; border-radius: 12px; max-width: 500px; margin: 20px; box-shadow: 0 10px 40px rgba(0,0,0,0.3); position: relative;">
|
|
<span class="close" onclick="closePaymentModal()" style="position: absolute; top: 15px; right: 20px; font-size: 28px; font-weight: bold; color: #999; cursor: pointer;">×</span>
|
|
<div style="text-align: center; padding: 40px 30px;">
|
|
<i class="fa-solid fa-exclamation-circle" style="font-size: 64px; color: #dc3545; margin-bottom: 20px;"></i>
|
|
<h2 style="color: #721c24; margin-bottom: 15px;">Payment Failed</h2>
|
|
<p style="margin-bottom: 10px; color: #333;">Your payment could not be processed. Please try again.</p>
|
|
<p style="font-size: 12px; color: #666; margin-bottom: 25px;">Order ID: '.htmlspecialchars($payment_return).'</p>
|
|
<button onclick="closePaymentModal()" class="btn" style="padding: 12px 30px;">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>';
|
|
}
|
|
}
|
|
}
|
|
|
|
$view .= '
|
|
<div class="content-title">
|
|
<div class="title">
|
|
<i class="fa-solid fa-box-open"></i>
|
|
<div class="txt">
|
|
<h2>'.$softwaretool_h2 .'</h2>
|
|
<p>'.$softwaretool_p.'</p>
|
|
</div>
|
|
</div>';
|
|
|
|
|
|
if (isset($_GET['equipmentID'])){$returnpage = 'equipment&equipmentID='.$_GET['equipmentID']; } else {$returnpage = 'dashboard';}
|
|
|
|
|
|
//SHOW BACK BUTTON ONLY FOR PORTAL USERS
|
|
if (isAllowed('dashboard',$_SESSION['authorization']['permissions'],$_SESSION['authorization']['permission'],'R') != 0){
|
|
$view .= '
|
|
<div class="title-actions">
|
|
<a href="index.php?page='.$returnpage.'" class="btn alt mar-right-2"><i class="fa-solid fa-arrow-left"></i></a>
|
|
<button class="btn" onclick="showInstructions()" style="">
|
|
<i class="fa-solid fa-circle-question"></i>
|
|
</button>
|
|
</div>
|
|
';
|
|
}
|
|
|
|
$view .= '
|
|
</div>';
|
|
|
|
$view .= '<div class="content-block">
|
|
|
|
<noscript>
|
|
<div style="background: #dc3545; color: white; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
|
|
<strong>JavaScript Required</strong><br>
|
|
This tool requires JavaScript to be enabled in your browser.
|
|
</div>
|
|
</noscript>
|
|
|
|
<p id="servicetoken" value="" hidden>'.$bearertoken.'</p>
|
|
|
|
<div id="connectdevice" style="display:flex; gap: 10px; margin-bottom: 20px;">
|
|
<button class="btn" id="connectButton" onClick="connectDeviceForSoftware()" style="min-width: 150px;">
|
|
<i class="fa-solid fa-plug"></i>
|
|
</button>
|
|
<div id="readStatus" style="flex: 1; background-color: #f1f1f1; border-radius: 4px; overflow: hidden;">
|
|
<div id="readBar" style="height: 100%; transition: width 0.3s ease;"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="Device_output" style="display:none;">
|
|
<div id="serialResults" style="font-family: monospace;white-space: pre;padding: 10px;background-color:#f1f1f1;display:none;"></div>
|
|
|
|
<div id="softwareCheckStatus" style="margin: 20px 0; padding: 20px; background-color:#f8f9fa; border-radius: 8px; text-align: center; display:none;">
|
|
<i class="fa-solid fa-spinner fa-spin" style="font-size: 24px; color: #04AA6D; margin-bottom: 10px;"></i>
|
|
<p id="checkingMessage" style="margin: 0; font-size: 16px;">'.$softwaretool_checking.'</p>
|
|
</div>
|
|
|
|
<div id="softwareOptionsContainer" style="margin-top: 20px; display:none; position: relative;">
|
|
<div id="softwareOptions" style="filter: blur(8px); pointer-events: none; opacity: 0.3; transition: all 0.3s ease;">
|
|
<h3 style="margin-bottom: 20px; color: #333;">'.$softwaretool_select_upgrade.'</h3>
|
|
<div id="softwareOptionsGrid" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; justify-content: center; max-width: 1200px; margin: 0 auto;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="noUpdatesMessage" style="margin: 20px 0; padding: 30px; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 3px; text-align: center; display:none; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);">
|
|
<i class="fa-solid fa-check-circle" style="font-size: 48px; margin-bottom: 15px; color: #28a745;"></i>
|
|
<p style="margin: 0; font-size: 18px; font-weight: 600; color: #155724;"><strong>'.$softwaretool_no_updates.'</strong></p>
|
|
<p style="margin: 10px 0 0 0; color: #6c757d; font-size: 14px;">Your device is up to date</p>
|
|
</div>
|
|
|
|
<div id="uploadSection" style="margin-top: 10px; display:none;">
|
|
<button class="btn" id="uploadSoftware" style="display:none;"
|
|
emergencyPlug-update verify
|
|
board="emergencyPlug"
|
|
port-filters= "[{usbVendorId: 1027, usbProductId: 24597}];"
|
|
disabled>Install Software
|
|
<span class="upload-progress"></span>
|
|
</button>
|
|
<!-- Hidden checkbox that upload.js expects -->
|
|
<input type="checkbox" id="action_firmware" style="display:none;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Help Modal -->
|
|
<div id="helpModal" style="display:none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center;">
|
|
<div style="background: white; border-radius: 12px; max-width: 600px; max-height: 80vh; overflow-y: auto; margin: 20px; box-shadow: 0 10px 40px rgba(0,0,0,0.3);">
|
|
<div style="padding: 25px; border-bottom: 1px solid #e0e0e0; display: flex; justify-content: space-between; align-items: center;">
|
|
<h3 style="margin: 0; color: #333;"><i class="fa-solid fa-circle-question"></i> '.$softwaretool_step.'</h3>
|
|
<button onclick="closeInstructions()" style="background: transparent; border: none; font-size: 20px; cursor: pointer; color: #666;"><i class="fa-solid fa-times"></i></button>
|
|
</div>
|
|
<div style="padding: 25px;">
|
|
<ol style="line-height: 1.8; color: #555;">
|
|
<li style="margin-bottom: 15px;">'.$softwaretool_step_1.'</li>
|
|
<li style="margin-bottom: 15px;">'.$softwaretool_step_2.'</li>
|
|
<li style="margin-bottom: 15px;">'.$softwaretool_step_3.'</li>
|
|
<li style="margin-bottom: 15px;">'.$softwaretool_step_4.'</li>
|
|
<li style="margin-bottom: 15px;">'.$softwaretool_step_5.'</li>
|
|
<li style="margin-bottom: 15px;">'.$softwaretool_step_6.'</li>
|
|
<li style="margin-bottom: 15px;">'.$softwaretool_step_7.'</li>
|
|
<li style="margin-bottom: 15px;">'.$softwaretool_step_8.'</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
';
|
|
|
|
$view .= '
|
|
</div>
|
|
</div>
|
|
';
|
|
|
|
$view .= '</div>';
|
|
//OUTPUT
|
|
echo $view;
|
|
|
|
// Output payment modal if exists
|
|
echo $payment_modal;
|
|
|
|
|
|
echo '
|
|
<script src="assets/upload.js?'.script_version.'"></script>
|
|
<script src="assets/softwaretool.js?'.script_version.'"></script>
|
|
<script>
|
|
var link = "'.$baseurl.'";
|
|
var DEBUG = '.(debug ? 'true' : 'false').';
|
|
var MOLLIE_ENABLED = '.(mollie_enabled ? 'true' : 'false').';
|
|
var PAYPAL_ENABLED = '.(paypal_enabled ? 'true' : 'false').';
|
|
var PAY_ON_DELIVERY_ENABLED = '.(pay_on_delivery_enabled ? 'true' : 'false').';
|
|
// Early browser compatibility check
|
|
if (!("serial" in navigator)) {
|
|
console.warn("Web Serial API is not supported in this browser");
|
|
}
|
|
// Translation variables
|
|
var TRANS_NAME = "'.($account_name ?? 'Name').'";
|
|
var TRANS_EMAIL = "'.($account_email ?? 'Email').'";
|
|
var TRANS_ADDRESS = "'.($shipping_address ?? 'Address').'";
|
|
var TRANS_CITY = "'.($shipping_city ?? 'City').'";
|
|
var TRANS_POSTAL = "'.($shipping_zip ?? 'Postal Code').'";
|
|
var TRANS_COUNTRY = "'.($shipping_country ?? 'Country').'";
|
|
var TRANS_USER_INFO_REQUIRED = "'.($user_information_required ?? 'User Information Required').'";
|
|
var TRANS_USER_INFO_DESCRIPTION = "'.($user_information_description ?? 'Please provide your information to continue with software updates').'";
|
|
var TRANS_CONTINUE = "'.($general_continue ?? 'Continue').'";
|
|
|
|
// Countries data
|
|
var COUNTRIES = '.json_encode($countries ?? []).';
|
|
|
|
var port, textEncoder, writableStreamClosed, writer, historyIndex = -1;
|
|
const lineHistory = [];
|
|
|
|
// Modal functions - defined globally for inline onclick
|
|
window.showInstructions = function() {
|
|
const modal = document.getElementById("helpModal");
|
|
if (modal) {
|
|
modal.style.display = "flex";
|
|
}
|
|
};
|
|
|
|
window.closeInstructions = function() {
|
|
const modal = document.getElementById("helpModal");
|
|
if (modal) {
|
|
modal.style.display = "none";
|
|
}
|
|
};
|
|
|
|
// Payment modal functions
|
|
window.closePaymentModal = function() {
|
|
const modal = document.getElementById("paymentModal");
|
|
if (modal) {
|
|
modal.style.display = "none";
|
|
// Clean URL by removing payment_return and order_id parameters
|
|
const url = new URL(window.location);
|
|
url.searchParams.delete("payment_return");
|
|
url.searchParams.delete("order_id");
|
|
window.history.replaceState({}, document.title, url);
|
|
}
|
|
};
|
|
|
|
// Close modal on background click
|
|
document.addEventListener("click", function(e) {
|
|
const helpModal = document.getElementById("helpModal");
|
|
if (helpModal && e.target === helpModal) {
|
|
closeInstructions();
|
|
}
|
|
const paymentModal = document.getElementById("paymentModal");
|
|
if (paymentModal && e.target === paymentModal) {
|
|
closePaymentModal();
|
|
}
|
|
});
|
|
|
|
// Monitor upload completion
|
|
const observer = new MutationObserver(function(mutations) {
|
|
mutations.forEach(function(mutation) {
|
|
if (mutation.type === "attributes" && mutation.attributeName === "checked") {
|
|
const actionFirmware = document.getElementById("action_firmware");
|
|
if (actionFirmware && actionFirmware.checked) {
|
|
console.log("Upload completion detected!");
|
|
// Upload completed successfully
|
|
handleUploadCompletion(true);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Also monitor for readBar changes to detect completion
|
|
const readBarObserver = new MutationObserver(function(mutations) {
|
|
mutations.forEach(function(mutation) {
|
|
if (mutation.type === "childList" || mutation.type === "characterData") {
|
|
const readBar = document.getElementById("readBar");
|
|
if (readBar && readBar.innerHTML && readBar.innerHTML.includes("Firmware update completed")) {
|
|
console.log("Firmware update completed detected via readBar!");
|
|
setTimeout(() => handleUploadCompletion(true), 500);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Start observing when upload section is visible
|
|
function startUploadMonitoring() {
|
|
const actionFirmware = document.getElementById("action_firmware");
|
|
const readBar = document.getElementById("readBar");
|
|
|
|
if (actionFirmware) {
|
|
observer.observe(actionFirmware, {
|
|
attributes: true,
|
|
attributeFilter: ["checked"]
|
|
});
|
|
console.log("Started monitoring action_firmware checkbox");
|
|
}
|
|
|
|
if (readBar) {
|
|
readBarObserver.observe(readBar, {
|
|
childList: true,
|
|
subtree: true,
|
|
characterData: true
|
|
});
|
|
console.log("Started monitoring readBar for completion");
|
|
}
|
|
}
|
|
|
|
// Handle upload completion (success or failure)
|
|
window.handleUploadCompletion = function(success) {
|
|
console.log("handleUploadCompletion called with success:", success);
|
|
|
|
const installStatus = document.getElementById("installationStatus");
|
|
const readBar = document.getElementById("readBar");
|
|
|
|
if (success) {
|
|
// Success handling
|
|
console.log("Updating UI for successful completion");
|
|
if (installStatus) {
|
|
installStatus.innerHTML = \'\' +
|
|
\'<i class="fa-solid fa-check-circle" style="font-size: 48px; color: #28a745; margin-bottom: 15px;"></i>\' +
|
|
\'<p style="margin: 0; font-size: 18px; font-weight: 600; color: #155724;">Installation Complete!</p>\' +
|
|
\'<p style="margin: 5px 0 0 0; color: #666; font-size: 14px;">Your device has been successfully updated</p>\';
|
|
}
|
|
// Ensure progress bar is at 100%
|
|
if (readBar) {
|
|
readBar.style.width = "100%";
|
|
readBar.style.background = "#04AA6D";
|
|
readBar.innerHTML = "Firmware update completed - 100%";
|
|
console.log("Updated readBar to 100%");
|
|
}
|
|
} else {
|
|
// Failure handling
|
|
console.log("Updating UI for failed completion");
|
|
if (installStatus) {
|
|
installStatus.innerHTML = \'\' +
|
|
\'<i class="fa-solid fa-exclamation-circle" style="font-size: 48px; color: #dc3545; margin-bottom: 15px;"></i>\' +
|
|
\'<p style="margin: 0; font-size: 18px; font-weight: 600; color: #721c24;">Installation Failed</p>\' +
|
|
\'<p style="margin: 5px 0 0 0; color: #666; font-size: 14px;">Please try again or contact support</p>\';
|
|
}
|
|
if (readBar) {
|
|
readBar.style.width = "100%";
|
|
readBar.style.background = "#dc3545";
|
|
readBar.innerHTML = "Installation failed";
|
|
}
|
|
}
|
|
|
|
// Stop monitoring
|
|
observer.disconnect();
|
|
readBarObserver.disconnect();
|
|
console.log("Stopped monitoring observers");
|
|
};
|
|
|
|
// Monitor for upload errors
|
|
window.addEventListener("error", function(e) {
|
|
if (e.message && e.message.includes("upload")) {
|
|
handleUploadCompletion(false);
|
|
}
|
|
});
|
|
</script>';
|
|
|
|
template_footer();
|
|
?>
|