286 lines
9.8 KiB
PHP
Executable file
286 lines
9.8 KiB
PHP
Executable file
<?php
|
|
require_once __DIR__ . "/session_bootstrap.php";
|
|
require_once "functions.php";
|
|
|
|
// Set a timestamp for when the page was loaded
|
|
$page_load_time = time();
|
|
|
|
// Refresh tokens only when necessary
|
|
if (isset($_SESSION["characters"]) && !empty($_SESSION["characters"])) {
|
|
// Only refresh tokens once every 5 minutes per user session
|
|
$last_token_refresh = $_SESSION['last_token_refresh'] ?? 0;
|
|
if ($page_load_time - $last_token_refresh > 300) {
|
|
foreach ($_SESSION["characters"] as $character_id => &$charData) {
|
|
if (isset($charData["refresh_token"])) {
|
|
if (
|
|
!isset($charData["access_token"]) ||
|
|
is_token_expired($charData["access_token"])
|
|
) {
|
|
$new_tokens = refresh_token($charData["refresh_token"]);
|
|
if (!empty($new_tokens["access_token"])) {
|
|
$charData["access_token"] = $new_tokens["access_token"];
|
|
} else {
|
|
error_log(
|
|
"Failed to refresh token for character ID $character_id"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
unset($charData);
|
|
$_SESSION['last_token_refresh'] = $page_load_time;
|
|
}
|
|
}
|
|
|
|
if (!isset($_SESSION["characters"]) || empty($_SESSION["characters"])) {
|
|
echo "No characters logged in. <a href='index.php'>Go back</a>";
|
|
exit();
|
|
}
|
|
|
|
// Check if we have a cached blueprint list
|
|
$cache_key = "all_character_blueprints";
|
|
$cached_data = get_cache_data($cache_key);
|
|
|
|
if ($cached_data !== null) {
|
|
$blueprints = $cached_data;
|
|
} else {
|
|
// Fetch blueprints for all characters
|
|
$blueprints = [];
|
|
$blueprint_ids = [];
|
|
|
|
foreach ($_SESSION["characters"] as $character_id => $charData) {
|
|
$access_token = $charData["access_token"] ?? null;
|
|
if (!$access_token) {
|
|
continue;
|
|
}
|
|
|
|
$character_blueprints = fetch_character_blueprints(
|
|
$character_id,
|
|
$access_token
|
|
);
|
|
foreach ($character_blueprints as $bp) {
|
|
$key =
|
|
$bp["blueprint_type_id"] .
|
|
"-" .
|
|
$bp["material_efficiency"] .
|
|
"-" .
|
|
$bp["time_efficiency"] .
|
|
"-" .
|
|
$bp["runs"];
|
|
$blueprints[$key] = $bp;
|
|
$blueprint_ids[] = $bp["blueprint_type_id"];
|
|
}
|
|
}
|
|
|
|
$blueprint_names = fetch_type_names(array_unique($blueprint_ids));
|
|
foreach ($blueprints as &$bp) {
|
|
$bp["blueprint_name"] =
|
|
$blueprint_names[$bp["blueprint_type_id"]] ?? "Unknown Blueprint";
|
|
}
|
|
unset($bp);
|
|
|
|
// Cache the results for 10 minutes
|
|
set_cache_data($cache_key, $blueprints, 600);
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Blueprints</title>
|
|
<style>
|
|
th.sorted-asc::after { content: " ▲"; }
|
|
th.sorted-desc::after { content: " ▼"; }
|
|
#blueprintsTable {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 20px;
|
|
table-layout: auto;
|
|
}
|
|
|
|
#blueprintsTable th,
|
|
#blueprintsTable td {
|
|
padding: 10px;
|
|
text-align: left;
|
|
border-bottom: 1px solid #333;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
min-width: 100px;
|
|
}
|
|
|
|
#blueprintsTable th {
|
|
background-color: #2a2a2a;
|
|
color: #00ffcc;
|
|
cursor: pointer;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 1;
|
|
}
|
|
|
|
#blueprintsTable tr:nth-child(even) {
|
|
background-color: #1e1e1e;
|
|
}
|
|
|
|
#blueprintsTable tr:hover {
|
|
background-color: #2c2c2c;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Blueprints</h1>
|
|
<table id="blueprintsTable" class="dashboard-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Blueprint Name</th>
|
|
<th>Material Efficiency</th>
|
|
<th>Time Efficiency</th>
|
|
<th>Number of Runs</th>
|
|
<th>Runs Remaining</th>
|
|
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($blueprints as $bp): ?>
|
|
<tr>
|
|
<td><?php echo htmlspecialchars(
|
|
$bp["blueprint_name"]
|
|
); ?></td>
|
|
<td><?php echo htmlspecialchars(
|
|
$bp["material_efficiency"]
|
|
); ?>%</td>
|
|
<td><?php echo htmlspecialchars(
|
|
$bp["time_efficiency"]
|
|
); ?>%</td>
|
|
<td><?php echo htmlspecialchars(
|
|
$bp["runs"] == -1 ? "Original" : $bp["runs"]
|
|
); ?></td>
|
|
<td><?php echo htmlspecialchars(
|
|
$bp["runs"] == -1 ? "∞" : $bp["runs"]
|
|
); ?></td>
|
|
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
let sortDirection = [];
|
|
|
|
document.getElementById('blueprintsTable').querySelector('thead').addEventListener('click', (event) => {
|
|
const th = event.target;
|
|
if (th.tagName === 'TH') {
|
|
const col = Array.from(th.parentNode.children).indexOf(th);
|
|
sortTable(col);
|
|
}
|
|
});
|
|
|
|
function sortTable(col) {
|
|
const table = document.getElementById("blueprintsTable");
|
|
const rows = Array.from(table.tBodies[0].rows);
|
|
const dir = (sortDirection[col] = !sortDirection[col]);
|
|
|
|
// Create a document fragment for better performance
|
|
const fragment = document.createDocumentFragment();
|
|
|
|
rows.sort((a, b) => {
|
|
const aCell = a.cells[col];
|
|
const bCell = b.cells[col];
|
|
const aText = aCell.textContent.trim();
|
|
const bText = bCell.textContent.trim();
|
|
|
|
if (!isNaN(aText) && !isNaN(bText)) {
|
|
return dir ? bText - aText : aText - bText;
|
|
}
|
|
|
|
return dir ? bText.localeCompare(aText) : aText.localeCompare(bText);
|
|
});
|
|
|
|
// Add rows to fragment
|
|
rows.forEach((row) => fragment.appendChild(row));
|
|
|
|
// Clear and append in a single operation
|
|
const tbody = table.tBodies[0];
|
|
tbody.innerHTML = '';
|
|
tbody.appendChild(fragment);
|
|
|
|
Array.from(table.querySelectorAll("th")).forEach((th, idx) => {
|
|
th.classList.remove("sorted-asc", "sorted-desc");
|
|
if (idx === col) {
|
|
th.classList.add(dir ? "sorted-desc" : "sorted-asc");
|
|
}
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
let sortDirection = [];
|
|
|
|
document.getElementById('blueprintsTable').querySelector('thead').addEventListener('click', (event) => {
|
|
const th = event.target;
|
|
if (th.tagName === 'TH') {
|
|
const col = Array.from(th.parentNode.children).indexOf(th);
|
|
sortTable(col);
|
|
}
|
|
});
|
|
|
|
function sortTable(col) {
|
|
const table = document.getElementById("blueprintsTable");
|
|
const rows = Array.from(table.tBodies[0].rows);
|
|
const dir = (sortDirection[col] = !sortDirection[col]);
|
|
|
|
rows.sort((a, b) => {
|
|
const aCell = a.cells[col];
|
|
const bCell = b.cells[col];
|
|
const aText = aCell.textContent.trim();
|
|
const bText = bCell.textContent.trim();
|
|
|
|
if (!isNaN(aText) && !isNaN(bText)) {
|
|
return dir ? bText - aText : aText - bText;
|
|
}
|
|
|
|
return dir ? bText.localeCompare(aText) : aText.localeCompare(bText);
|
|
});
|
|
|
|
rows.forEach((row) => table.tBodies[0].appendChild(row));
|
|
|
|
Array.from(table.querySelectorAll("th")).forEach((th, idx) => {
|
|
th.classList.remove("sorted-asc", "sorted-desc");
|
|
if (idx === col) {
|
|
th.classList.add(dir ? "sorted-desc" : "sorted-asc");
|
|
}
|
|
});
|
|
}
|
|
|
|
// Session keep-alive mechanism
|
|
function keepSessionAlive() {
|
|
// Add cache-busting parameter to prevent browser caching
|
|
fetch("keep_alive.php?t=" + Date.now())
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.status !== "success") {
|
|
console.error("Failed to refresh session:", data.message);
|
|
}
|
|
})
|
|
.catch(error => console.error("Error in keep-alive request:", error));
|
|
}
|
|
|
|
// Call keepSessionAlive only if the user is active
|
|
let sessionTimer;
|
|
const resetSessionTimer = () => {
|
|
clearTimeout(sessionTimer);
|
|
sessionTimer = setTimeout(keepSessionAlive, 300000); // 5 minutes
|
|
};
|
|
|
|
// Reset timer on user activity
|
|
['mousemove', 'keydown', 'click', 'scroll'].forEach(event => {
|
|
document.addEventListener(event, resetSessionTimer, false);
|
|
});
|
|
|
|
// Initial setup
|
|
resetSessionTimer();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|