ProductionGame/frontend/js/ui/inspectorView.js

141 lines
7.1 KiB
JavaScript

// Production - The Idle Game: Desktop Inspector & Supply Chain Analytics Panel
import { PRODUCTS, SECTORS, getProduct } from '../data/products.js';
import { fmtCurrency, fmtNum } from '../core/formatters.js';
export function renderInspector(container, state, onAction) {
const selectedId = state.selectedProductId || 'wheat';
const product = getProduct(selectedId) || PRODUCTS[0];
const pState = state.products[product.id] || { stock: 0, lines: 0, logistics: 0, unlocked: false };
const sector = SECTORS.find(s => s.id === product.sector);
// Find downstream products that consume this product
const downstream = PRODUCTS.filter(p => p.inputs && p.inputs.some(inp => inp.id === product.id));
// Calculate liquidation value
const totalLiquidationValue = (pState.stock || 0) * product.basePrice;
const halfLiquidationValue = totalLiquidationValue * 0.5;
let html = `
<div class="inspector-card">
<div class="inspector-header">
<div class="inspector-badge-row">
<span class="sector-tag" style="background: ${product.color}15; color: ${product.color};">
<iconify-icon icon="${product.icon}"></iconify-icon> ${sector?.name}
</span>
<span class="tier-tag">Tier ${product.tier}</span>
</div>
<h3 class="inspector-title">${product.name}</h3>
<p class="inspector-desc">${product.description}</p>
</div>
<!-- Real-time metrics grid -->
<div class="inspector-metrics-grid">
<div class="metric-box">
<span class="metric-label">Warehouse Stock:</span>
<strong class="metric-val font-mono">${fmtNum(pState.stock, 0)} ${product.unit}</strong>
</div>
<div class="metric-box">
<span class="metric-label">Wholesale Price:</span>
<strong class="metric-val font-mono">${fmtCurrency(product.basePrice)}</strong>
</div>
<div class="metric-box">
<span class="metric-label">Production Lines:</span>
<strong class="metric-val font-mono">${pState.lines} active</strong>
</div>
<div class="metric-box">
<span class="metric-label">Logistics Fleets:</span>
<strong class="metric-val font-mono">${pState.logistics || 0} active</strong>
</div>
</div>
<!-- Instant Wholesale Market Liquidation -->
<div class="inspector-section">
<h4 class="section-heading">
<iconify-icon icon="lucide:dollar-sign"></iconify-icon> Instant Wholesale Liquidation
</h4>
<p class="section-subtext">Liquidate stockpiles immediately onto the wholesale spot market.</p>
<div class="liquidation-buttons">
<button class="btn-corp-secondary btn-liquidate-half" data-product="${product.id}" ${pState.stock >= 2 ? '' : 'disabled'}>
Sell 50% (${fmtCurrency(halfLiquidationValue)})
</button>
<button class="btn-primary-corp btn-liquidate-all" data-product="${product.id}" ${pState.stock >= 1 ? '' : 'disabled'}>
Sell 100% (${fmtCurrency(totalLiquidationValue)})
</button>
</div>
</div>
<!-- Upstream & Downstream Supply Chain Flow -->
<div class="inspector-section">
<h4 class="section-heading">
<iconify-icon icon="lucide:git-fork"></iconify-icon> Supply Chain Dependencies
</h4>
<!-- Inputs (Upstream) -->
<div class="chain-box">
<span class="chain-title">Direct Inputs:</span>
${(!product.inputs || product.inputs.length === 0) ? `
<div class="chain-empty">Primary commodity &bull; Direct extraction from natural deposits.</div>
` : `
<div class="chain-items">
${product.inputs.map(inp => {
const parent = getProduct(inp.id);
const parentStock = state.products[inp.id]?.stock || 0;
return `
<div class="chain-item-row" data-product="${parent.id}">
<div class="chain-item-left">
<iconify-icon icon="${parent.icon}" style="color: ${parent.color};"></iconify-icon>
<span>${parent.name}</span>
</div>
<span class="chain-item-ratio font-mono">${inp.amount} per unit (${fmtNum(parentStock, 0)} on hand)</span>
</div>
`;
}).join('')}
</div>
`}
</div>
<!-- Downstream Consumers -->
<div class="chain-box">
<span class="chain-title">Downstream Consumers:</span>
${downstream.length === 0 ? `
<div class="chain-empty">End-tier consumer or industrial finished product.</div>
` : `
<div class="chain-items">
${downstream.map(child => {
const isUnlocked = state.products[child.id]?.unlocked;
return `
<div class="chain-item-row" data-product="${child.id}">
<div class="chain-item-left">
<iconify-icon icon="${child.icon}" style="color: ${child.color};"></iconify-icon>
<span>${child.name}</span>
</div>
<span class="chain-badge ${isUnlocked ? 'badge-open' : 'badge-locked'}">
${isUnlocked ? 'Active' : 'Locked'}
</span>
</div>
`;
}).join('')}
</div>
`}
</div>
</div>
</div>
`;
container.innerHTML = html;
const halfBtn = container.querySelector('.btn-liquidate-half');
if (halfBtn) {
halfBtn.onclick = () => onAction({ type: 'LIQUIDATE_STOCK', productId: product.id, ratio: 0.5 });
}
const allBtn = container.querySelector('.btn-liquidate-all');
if (allBtn) {
allBtn.onclick = () => onAction({ type: 'LIQUIDATE_STOCK', productId: product.id, ratio: 1.0 });
}
container.querySelectorAll('.chain-item-row').forEach(row => {
row.onclick = () => onAction({ type: 'SELECT_PRODUCT', productId: row.dataset.product });
});
}