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>
 |