feat: Implement invoice generation and emailing functionality
- Added invoice generation logic using DomPDF. - Integrated invoice data retrieval from the API. - Implemented language determination for invoices based on customer data. - Added options to email invoices to customers and admin. - Included HTML output option for direct viewing in the browser. - Ensured proper redirection and error handling throughout the process.
This commit is contained in:
@@ -1672,7 +1672,7 @@ function overviewIndicators($warranty, $service, $sw_version, $sw_version_latest
|
||||
$indicator .= '<span class="dot" style="background-color: #13b368;">F</span>';
|
||||
} else {
|
||||
if ($sw_version == ''){
|
||||
$indicator .= '<span class="dot" style="background-color: #81848a">F</span>';
|
||||
$indicator .= '<span class="dot" style="background-color: #13b368;">F</span>';
|
||||
} else {
|
||||
$indicator .= '<span class="dot" style="background-color: #eb8a0d;">F</span>';
|
||||
}
|
||||
@@ -1777,7 +1777,7 @@ function availableFirmware($sw_version,$sw_version_latest){
|
||||
break;
|
||||
|
||||
default:
|
||||
$message ='<span class="status">Unknown</span>';
|
||||
$message ='<span class="status">✓</span>';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5339,10 +5339,12 @@ function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') {
|
||||
$customer_country = $customer['address_country'] ?? '';
|
||||
|
||||
// Extract transaction data
|
||||
$payment_amount = $invoice_data['payment_amount'] ?? 0;
|
||||
$tax_amount = $invoice_data['tax_amount'] ?? 0;
|
||||
$shipping_amount = $invoice_data['shipping_amount'] ?? 0;
|
||||
$discount_amount = $invoice_data['discount_amount'] ?? 0;
|
||||
$pricing = $invoice_data['pricing'] ?? [];
|
||||
$payment_amount = $pricing['payment_amount'] ?? $invoice_data['payment_amount'] ?? 0;
|
||||
$tax_amount = $pricing['tax_total'] ?? $invoice_data['tax_amount'] ?? 0;
|
||||
$shipping_amount = $pricing['shipping_total'] ?? $invoice_data['shipping_amount'] ?? 0;
|
||||
$discount_amount = $pricing['discount_total'] ?? $invoice_data['discount_amount'] ?? 0;
|
||||
$subtotal_amount = $pricing['subtotal'] ?? 0;
|
||||
$currency = 'EUR'; // Default currency
|
||||
$invoice_date = $invoice_data['invoice_created'] ?? date('Y-m-d H:i:s');
|
||||
|
||||
@@ -5373,6 +5375,39 @@ function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') {
|
||||
'serial_number' => $serial_number,
|
||||
'license_key' => $license_key
|
||||
];
|
||||
} elseif (isset($invoice_data['products']) && is_array($invoice_data['products'])) {
|
||||
// New format with products array
|
||||
$pdo = dbConnect($dbname);
|
||||
|
||||
foreach ($invoice_data['products'] as $product) {
|
||||
$product_code = $product['productcode'] ?? null;
|
||||
$product_name = $product['product_name'] ?? null;
|
||||
$product_options = $product['options'] ?? [];
|
||||
$product_serial = $product_options['serial_number'] ?? null;
|
||||
|
||||
// Handle case where productcode and product_name are empty but serial_number exists
|
||||
if ((empty($product_code) || $product_code === null) &&
|
||||
(empty($product_name) || $product_name === null) &&
|
||||
!empty($product_serial)) {
|
||||
$product_code = 'License';
|
||||
$product_name = 'software license for ' . $product_serial;
|
||||
}
|
||||
|
||||
// Get license key from database
|
||||
$sql = 'SELECT license_key FROM products_software_licenses WHERE transaction_id = ? LIMIT 1';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$order_id]);
|
||||
$license_result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$license_key = $license_result['license_key'] ?? 'Pending';
|
||||
|
||||
$items[] = [
|
||||
'name' => $product_name ?? 'Software Upgrade',
|
||||
'quantity' => $product['quantity'] ?? 1,
|
||||
'price' => $product['price'] ?? 0,
|
||||
'serial_number' => $product_serial ?? 'N/A',
|
||||
'license_key' => $license_key
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Load language translations
|
||||
@@ -5402,127 +5437,319 @@ function generateSoftwareInvoice($invoice_data, $order_id, $language = 'US') {
|
||||
$lbl_license_key = $translations['license_key'] ?? 'License Key';
|
||||
$lbl_license_expiry = $translations['license_expiry'] ?? 'License Expiry';
|
||||
|
||||
// Subtotal calculation - use from pricing data or calculate from items
|
||||
if ($subtotal_amount > 0) {
|
||||
$subtotal = $subtotal_amount;
|
||||
} else {
|
||||
// Calculate from items if not provided
|
||||
$subtotal = 0;
|
||||
foreach ($items as $item) {
|
||||
$subtotal += $item['price'] * $item['quantity'];
|
||||
}
|
||||
}
|
||||
|
||||
// Build HTML invoice
|
||||
$html = '<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="' . strtolower($language) . '">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>' . htmlspecialchars($lbl_invoice) . ' - Total Safety Solutions</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; font-size: 12px; color: #333; }
|
||||
.invoice-header { margin-bottom: 30px; }
|
||||
.invoice-title { font-size: 24px; font-weight: bold; margin-bottom: 10px; }
|
||||
.invoice-info { margin-bottom: 20px; }
|
||||
.customer-info { margin-bottom: 20px; background: #f5f5f5; padding: 15px; }
|
||||
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
|
||||
th { background: #4CAF50; color: white; padding: 10px; text-align: left; }
|
||||
td { padding: 10px; border-bottom: 1px solid #ddd; }
|
||||
.text-right { text-align: right; }
|
||||
.total-row { font-weight: bold; background: #f9f9f9; }
|
||||
.license-info { background: #e3f2fd; padding: 15px; margin-top: 20px; border-left: 4px solid #2196F3; }
|
||||
.footer { margin-top: 40px; text-align: center; font-size: 10px; color: #666; }
|
||||
@page {margin: 220px 50px; }
|
||||
|
||||
body {
|
||||
font-family: "DejaVu Sans", Arial, sans-serif;
|
||||
color: #000;
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#header {
|
||||
position: fixed;
|
||||
left: -52px;
|
||||
top: -220px;
|
||||
right: -50px;
|
||||
height: 200px;
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#header img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#footer {
|
||||
position: fixed;
|
||||
left: -50px;
|
||||
bottom: -250px;
|
||||
right: -50px;
|
||||
height: 150px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#footer img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.invoice-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #2c5f5d;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.company-header {
|
||||
display: table;
|
||||
width: 100%;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.company-info, .contact-details {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.company-info h3 {
|
||||
font-weight: bold;
|
||||
margin: 0 0 5px 0;
|
||||
color: #2c5f5d;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.company-info p, .contact-details p {
|
||||
margin: 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.contact-details {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.contact-details h3 {
|
||||
font-weight: bold;
|
||||
margin: 0 0 5px 0;
|
||||
color: #2c5f5d;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.invoice-details {
|
||||
display: table;
|
||||
width: 100%;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.invoice-left, .invoice-right {
|
||||
display: table-cell;
|
||||
vertical-align: top;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.invoice-right {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
margin-bottom: 2px;
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
display: table-cell;
|
||||
font-weight: normal;
|
||||
width: 140px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.items-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 30px;
|
||||
border-bottom: 1px solid #999;
|
||||
}
|
||||
|
||||
.items-table th {
|
||||
padding: 8px 6px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.items-table td {
|
||||
padding: 6px;
|
||||
border-bottom: 1px solid #999;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.items-table .qty-col {
|
||||
text-align: center;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.items-table .price-col, .items-table .total-col {
|
||||
text-align: right;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.items-table th.qty-col {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.items-table th.price-col, .items-table th.total-col {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.totals-section {
|
||||
float: right;
|
||||
width: 250px;
|
||||
margin-top: 20px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.total-row {
|
||||
display: table;
|
||||
width: 100%;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.total-label {
|
||||
display: table-cell;
|
||||
text-align: left;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
display: table-cell;
|
||||
text-align: right;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.final-total {
|
||||
border-top: 1px solid #000;
|
||||
padding-top: 5px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.final-total .total-amount {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="invoice-header">
|
||||
<div class="invoice-title">' . htmlspecialchars($lbl_invoice) . '</div>
|
||||
<div class="invoice-info">
|
||||
<strong>' . htmlspecialchars($lbl_invoice_number) . ':</strong> ' . htmlspecialchars($order_id) . '<br>
|
||||
<strong>' . htmlspecialchars($lbl_invoice_date) . ':</strong> ' . htmlspecialchars(date('Y-m-d', strtotime($invoice_date))) . '
|
||||
<div id="header">
|
||||
<img src="https://'.$portalURL.'/assets/images/TSS_invoice_header.png" alt="Invoice header">
|
||||
</div>
|
||||
<div id="footer">
|
||||
<img src="https://'.$portalURL.'/assets/images/TSS_invoice_footer.png" alt="Invoice footer">
|
||||
</div>
|
||||
|
||||
<div class="invoice-title">' . htmlspecialchars($lbl_invoice) . '</div>
|
||||
|
||||
<div class="company-header">
|
||||
<div class="company-info">
|
||||
<h3>Total Safety Solutions B.V.</h3>
|
||||
<p>Laarakkerweg 8</p>
|
||||
<p>5061 JR OISTERWIJK</p>
|
||||
<p>Nederland</p>
|
||||
</div>
|
||||
<div class="contact-details">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="customer-info">
|
||||
<strong>' . htmlspecialchars($lbl_customer) . ':</strong><br>
|
||||
' . htmlspecialchars($customer_name) . '<br>';
|
||||
|
||||
if ($customer_address) {
|
||||
$html .= htmlspecialchars($customer_address) . '<br>';
|
||||
}
|
||||
if ($customer_city || $customer_zip) {
|
||||
$html .= htmlspecialchars($customer_zip . ' ' . $customer_city) . '<br>';
|
||||
}
|
||||
if ($customer_state) {
|
||||
$html .= htmlspecialchars($customer_state) . '<br>';
|
||||
}
|
||||
if ($customer_country) {
|
||||
$html .= htmlspecialchars($customer_country) . '<br>';
|
||||
}
|
||||
|
||||
$html .= htmlspecialchars($customer_email) . '
|
||||
<div class="invoice-details">
|
||||
<div class="invoice-left">
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Invoice Date</div>
|
||||
<div class="detail-value">: ' . htmlspecialchars(date('d-m-Y', strtotime($invoice_date))) . '</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Invoice Number</div>
|
||||
<div class="detail-value">: ' . htmlspecialchars($order_id) . '</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="invoice-right">
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Reference</div>
|
||||
<div class="detail-value">: Online order</div>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<div class="detail-label">Order number</div>
|
||||
<div class="detail-value">: ' . htmlspecialchars($order_id) . '</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<table class="items-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>' . htmlspecialchars($lbl_product) . '</th>
|
||||
<th class="text-right">' . htmlspecialchars($lbl_quantity) . '</th>
|
||||
<th class="text-right">' . htmlspecialchars($lbl_price) . '</th>
|
||||
<th>Item code</th>
|
||||
<th>Description</th>
|
||||
<th class="qty-col">Quantity</th>
|
||||
<th class="price-col">Price</th>
|
||||
<th class="total-col">Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>';
|
||||
|
||||
foreach ($items as $item) {
|
||||
$line_total = $item['price'] * $item['quantity'];
|
||||
$html .= '<tr>
|
||||
<td>' . htmlspecialchars($item['name']) . '</td>
|
||||
<td class="text-right">' . htmlspecialchars($item['quantity']) . '</td>
|
||||
<td class="text-right">' . number_format($item['price'], 2) . ' ' . htmlspecialchars($currency) . '</td>
|
||||
</tr>';
|
||||
<td>SOFTWARE</td>
|
||||
<td>' . htmlspecialchars($item['name']);
|
||||
|
||||
if ($item['serial_number'] !== 'N/A') {
|
||||
$html .= '<br><small>Serial: ' . htmlspecialchars($item['serial_number']) . '</small>';
|
||||
}
|
||||
if ($item['license_key'] !== 'Pending') {
|
||||
$html .= '<br><small>License: ' . htmlspecialchars($item['license_key']) . '</small>';
|
||||
}
|
||||
|
||||
$html .= '</td>
|
||||
<td class="qty-col">' . htmlspecialchars($item['quantity']) . ' </td>
|
||||
<td class="price-col">€ ' . number_format($item['price'], 2) . '</td>
|
||||
<td class="total-col">€ ' . number_format($line_total, 2) . '</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
// Subtotal
|
||||
$subtotal = $payment_amount - $tax_amount - $shipping_amount + $discount_amount;
|
||||
$html .= '<tr>
|
||||
<td colspan="2" class="text-right"><strong>' . htmlspecialchars($lbl_subtotal) . ':</strong></td>
|
||||
<td class="text-right">' . number_format($subtotal, 2) . ' ' . htmlspecialchars($currency) . '</td>
|
||||
</tr>';
|
||||
|
||||
// Tax
|
||||
if ($tax_amount > 0) {
|
||||
$html .= '<tr>
|
||||
<td colspan="2" class="text-right"><strong>' . htmlspecialchars($lbl_tax) . ':</strong></td>
|
||||
<td class="text-right">' . number_format($tax_amount, 2) . ' ' . htmlspecialchars($currency) . '</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
// Shipping
|
||||
if ($shipping_amount > 0) {
|
||||
$html .= '<tr>
|
||||
<td colspan="2" class="text-right"><strong>' . htmlspecialchars($lbl_shipping) . ':</strong></td>
|
||||
<td class="text-right">' . number_format($shipping_amount, 2) . ' ' . htmlspecialchars($currency) . '</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
// Discount
|
||||
if ($discount_amount > 0) {
|
||||
$html .= '<tr>
|
||||
<td colspan="2" class="text-right"><strong>' . htmlspecialchars($lbl_discount) . ':</strong></td>
|
||||
<td class="text-right">-' . number_format($discount_amount, 2) . ' ' . htmlspecialchars($currency) . '</td>
|
||||
</tr>';
|
||||
}
|
||||
|
||||
// Total
|
||||
$html .= '<tr class="total-row">
|
||||
<td colspan="2" class="text-right"><strong>' . htmlspecialchars($lbl_total) . ':</strong></td>
|
||||
<td class="text-right"><strong>' . number_format($payment_amount, 2) . ' ' . htmlspecialchars($currency) . '</strong></td>
|
||||
</tr>';
|
||||
|
||||
$html .= '</tbody>
|
||||
</table>';
|
||||
</table>
|
||||
|
||||
// License information
|
||||
if ($license_key && $serial_number) {
|
||||
$html .= '<div class="license-info">
|
||||
<strong>Software License Information:</strong><br>
|
||||
<strong>' . htmlspecialchars($lbl_device_serial) . ':</strong> ' . htmlspecialchars($serial_number) . '<br>
|
||||
<strong>' . htmlspecialchars($lbl_license_key) . ':</strong> ' . htmlspecialchars($license_key) . '<br>
|
||||
<strong>' . htmlspecialchars($lbl_license_expiry) . ':</strong> 2099-12-31
|
||||
</div>';
|
||||
<div class="totals-section">
|
||||
<div class="total-row">
|
||||
<div class="total-label">' . htmlspecialchars($lbl_subtotal) . '</div>
|
||||
<div class="total-amount">€ ' . number_format($subtotal, 2) . '</div>
|
||||
</div>';
|
||||
|
||||
if ($tax_amount > 0) {
|
||||
$html .= '<div class="total-row">
|
||||
<div class="total-label">' . htmlspecialchars($lbl_tax) . '</div>
|
||||
<div class="total-amount">€ ' . number_format($tax_amount, 2) . '</div>
|
||||
</div>';
|
||||
} else {
|
||||
$html .= '<div class="total-row">
|
||||
<div class="total-label">VAT</div>
|
||||
<div class="total-amount">included</div>
|
||||
</div>';
|
||||
}
|
||||
|
||||
$html .= '<div class="footer">
|
||||
Thank you for your purchase!<br>
|
||||
This invoice was generated automatically.
|
||||
|
||||
$html .= '<div class="total-row final-total">
|
||||
<div class="total-label">' . htmlspecialchars($lbl_total) . '</div>
|
||||
<div class="total-amount">€ ' . number_format($payment_amount, 2) . '</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
|
||||
BIN
assets/images/TSS_invoice_footer.png
Normal file
BIN
assets/images/TSS_invoice_footer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
BIN
assets/images/TSS_invoice_header.png
Normal file
BIN
assets/images/TSS_invoice_header.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 190 KiB |
BIN
assets/mollie/.DS_Store
vendored
BIN
assets/mollie/.DS_Store
vendored
Binary file not shown.
BIN
assets/mollie/src/.DS_Store
vendored
BIN
assets/mollie/src/.DS_Store
vendored
Binary file not shown.
@@ -119,7 +119,10 @@ async function connectDevice() {
|
||||
// Log connection failure details
|
||||
await logCommunication(`Serial connection failed: ${error.message || 'Unknown error'}`, 'disconnected');
|
||||
|
||||
if (openPort = 1){
|
||||
// Check for specific "No port selected" error and show user-friendly message
|
||||
if (error.message && error.message.includes('No port selected by the user')) {
|
||||
progressBar("100", "No device selected, please try again", "#ff6666");
|
||||
} else if (openPort = 1){
|
||||
closePort();
|
||||
console.log("Closing port");
|
||||
alert("System is still trying to close the serial port. If this message continues to come up please refresh this page.");
|
||||
|
||||
@@ -161,7 +161,13 @@ async function connectDeviceForSoftware() {
|
||||
|
||||
} catch (error) {
|
||||
await logCommunication(`Connection error: ${error.message}`, 'error');
|
||||
progressBar("0", "Error: " + error.message, "#ff6666");
|
||||
|
||||
// Check for specific "No port selected" error and show user-friendly message
|
||||
if (error.message && error.message.includes('No port selected by the user')) {
|
||||
progressBar("100", "No device selected, please try again", "#ff6666");
|
||||
} else {
|
||||
progressBar("100", "Error: " + error.message, "#ff6666");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1193,14 +1199,50 @@ async function downloadAndInstallSoftware(option, customerData = null) {
|
||||
console.log("Click the 'Install Software' button to test if upload.js can handle the file");
|
||||
alert("DEBUG MODE: Download complete!\n\nBlob size: " + blob.size + " bytes\n\nClick the 'Install Software' button to test upload.js");
|
||||
} else {
|
||||
// PRODUCTION MODE: Show upload button and automatically trigger
|
||||
// PRODUCTION MODE: Hide button and show installation in progress
|
||||
document.getElementById("uploadSection").style.display = "block";
|
||||
const uploadBtn = document.getElementById("uploadSoftware");
|
||||
uploadBtn.style.display = "block";
|
||||
uploadBtn.disabled = false;
|
||||
uploadBtn.style.display = "none";
|
||||
|
||||
// Hide device version information during installation
|
||||
const softwareOptions = document.getElementById("softwareOptions");
|
||||
if (softwareOptions) {
|
||||
softwareOptions.style.display = "none";
|
||||
}
|
||||
|
||||
// Create installation status indicator
|
||||
const installStatus = document.createElement("div");
|
||||
installStatus.id = "installationStatus";
|
||||
installStatus.style.cssText = `
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
border-radius: 8px;
|
||||
margin: 10px 0;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
`;
|
||||
installStatus.innerHTML = `
|
||||
<i class="fa-solid fa-spinner fa-spin" style="font-size: 32px; color: #04AA6D; margin-bottom: 10px;"></i>
|
||||
<p style="margin: 0; font-size: 18px; font-weight: 600; color: #333;">Installing Software...</p>
|
||||
<p style="margin: 5px 0 0 0; color: #666; font-size: 14px;">Please keep your device connected and do not close this page</p>
|
||||
`;
|
||||
|
||||
// Insert status before the hidden upload section
|
||||
document.getElementById("uploadSection").parentNode.insertBefore(installStatus, document.getElementById("uploadSection"));
|
||||
|
||||
progressBar("60", "Ready to install, starting upload...", "#04AA6D");
|
||||
uploadBtn.click();
|
||||
progressBar("60", "Starting automatic installation...", "#04AA6D");
|
||||
|
||||
// Enable the upload button and automatically click it
|
||||
setTimeout(() => {
|
||||
uploadBtn.disabled = false;
|
||||
|
||||
// Start monitoring for completion
|
||||
if (typeof startUploadMonitoring === 'function') {
|
||||
startUploadMonitoring();
|
||||
}
|
||||
|
||||
uploadBtn.click();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user