ProductionGame/frontend/js/ui/boardroomView.js

149 lines
7.2 KiB
JavaScript

// Production - The Idle Game: Corporate IPO & Boardroom Perks View
// Fine-grained DOM updates without innerHTML teardowns
import { BOARDROOM_PERKS, calculateSharesEarned, IPO_MIN_VALUATION } from '../data/boardroom.js';
import { fmtCurrency, fmtNum } from '../core/formatters.js';
export function mountBoardroom(container, state, onAction) {
const earnedShares = calculateSharesEarned(state.lifetimeRevenue);
const canIPO = state.lifetimeRevenue >= IPO_MIN_VALUATION;
const perks = state.boardroomPerks || {};
let html = `
<div class="boardroom-header-pane">
<div class="boardroom-hero">
<div class="hero-left">
<span class="executive-tag">
<iconify-icon icon="lucide:building-2"></iconify-icon> Executive Boardroom
</span>
<h2 class="boardroom-title">Corporate IPO & Venture Capital</h2>
<p class="boardroom-desc">
Take your manufacturing conglomerate public on the global securities exchange.
Liquidate current factories to secure permanent <strong>Venture Shares ($V-Shares)</strong>, funding cutting-edge R&D and boardroom privileges.
</p>
</div>
<div class="hero-valuation-card">
<div class="val-label">Corporate Enterprise Valuation</div>
<div class="val-number font-mono" id="boardroom-val-number">${fmtCurrency(state.valuation)}</div>
<div class="val-lifetime">Lifetime Gross Revenue: <strong id="boardroom-val-lifetime">${fmtCurrency(state.lifetimeRevenue)}</strong></div>
</div>
</div>
<div class="ipo-action-banner ${canIPO ? 'ready-ipo' : 'locked-ipo'}" id="boardroom-ipo-banner">
<div class="ipo-banner-info">
<div class="ipo-shares-badge font-mono">
<iconify-icon icon="lucide:gem"></iconify-icon>
<span id="boardroom-earned-shares">+${fmtNum(earnedShares, 0)} $V-Shares</span>
</div>
<div>
<h4 class="ipo-banner-title">Initial Public Offering (IPO) Ready</h4>
<p class="ipo-banner-sub" id="boardroom-ipo-sub">
${canIPO
? `Execute corporate IPO now to claim ${fmtNum(earnedShares, 0)} Venture Shares and restart with permanent bonuses.`
: `Requires minimum ${fmtCurrency(IPO_MIN_VALUATION)} in lifetime revenue to file for IPO.`}
</p>
</div>
</div>
<button class="btn-primary-corp btn-ipo-trigger" id="boardroom-btn-ipo" ${canIPO ? '' : 'disabled'}>
<iconify-icon icon="lucide:trending-up"></iconify-icon>
<span>Launch IPO</span>
</button>
</div>
</div>
<div class="boardroom-shares-summary">
<div class="shares-pill">
<span class="shares-label">Available $V-Shares:</span>
<strong class="shares-val font-mono"><iconify-icon icon="lucide:gem"></iconify-icon> <span id="boardroom-avail-shares">${fmtNum(state.ventureShares, 0)}</span></strong>
</div>
<div class="shares-pill">
<span class="shares-label">IPOs Completed:</span>
<strong class="shares-val font-mono" id="boardroom-ipos-completed">${state.ipoCount || 0}</strong>
</div>
</div>
<div class="perks-section-title">
<h3><iconify-icon icon="lucide:shield-check"></iconify-icon> Boardroom R&D Tech Tree</h3>
<span>Permanent corporate privileges that persist across all future IPO expansions</span>
</div>
<div class="perks-grid">
`;
for (const perk of BOARDROOM_PERKS) {
const currentLvl = perks[perk.id] || 0;
const isMaxed = currentLvl >= perk.maxLevel;
const nextCost = !isMaxed ? perk.costShares[currentLvl] : 0;
const canAfford = state.ventureShares >= nextCost && !isMaxed;
html += `
<div class="perk-card ${isMaxed ? 'perk-maxed' : ''}" id="perk-card-${perk.id}">
<div class="perk-header">
<div class="perk-icon-wrap" style="background: ${perk.color}15; color: ${perk.color};">
<iconify-icon icon="${perk.icon}" class="icon-lg"></iconify-icon>
</div>
<div>
<div class="perk-tier-badge" id="perk-tier-${perk.id}">Level ${currentLvl} / ${perk.maxLevel}</div>
<h4 class="perk-name">${perk.name}</h4>
</div>
</div>
<p class="perk-desc">${perk.description}</p>
<div class="perk-effect-box">
<iconify-icon icon="lucide:zap" style="color: ${perk.color};"></iconify-icon>
<span>${perk.effectDesc}</span>
</div>
<div class="perk-footer">
<button class="btn-corp-perk btn-buy-perk" id="btn-perk-${perk.id}" data-perk="${perk.id}" ${canAfford ? '' : 'disabled'}>
<iconify-icon icon="lucide:gem"></iconify-icon>
<span id="btn-perk-text-${perk.id}">${isMaxed ? 'Max Tier Acquired' : `Upgrade (${fmtNum(nextCost, 0)} $V-Shares)`}</span>
</button>
</div>
</div>
`;
}
html += `</div>`;
container.innerHTML = html;
const ipoBtn = container.querySelector('.btn-ipo-trigger');
if (ipoBtn) {
ipoBtn.onclick = () => onAction({ type: 'TRIGGER_IPO' });
}
container.querySelectorAll('.btn-buy-perk').forEach(btn => {
btn.onclick = () => onAction({ type: 'BUY_PERK', perkId: btn.dataset.perk });
});
}
export function updateBoardroom(container, state) {
const earnedShares = calculateSharesEarned(state.lifetimeRevenue);
const canIPO = state.lifetimeRevenue >= IPO_MIN_VALUATION;
const perks = state.boardroomPerks || {};
const elVal = document.getElementById('boardroom-val-number');
if (elVal) elVal.textContent = fmtCurrency(state.valuation);
const elLifetime = document.getElementById('boardroom-val-lifetime');
if (elLifetime) elLifetime.textContent = fmtCurrency(state.lifetimeRevenue);
const elEarned = document.getElementById('boardroom-earned-shares');
if (elEarned) elEarned.textContent = `+${fmtNum(earnedShares, 0)} $V-Shares`;
const btnIPO = document.getElementById('boardroom-btn-ipo');
if (btnIPO) btnIPO.disabled = !canIPO;
const elAvail = document.getElementById('boardroom-avail-shares');
if (elAvail) elAvail.textContent = fmtNum(state.ventureShares, 0);
for (const perk of BOARDROOM_PERKS) {
const currentLvl = perks[perk.id] || 0;
const isMaxed = currentLvl >= perk.maxLevel;
const nextCost = !isMaxed ? perk.costShares[currentLvl] : 0;
const canAfford = state.ventureShares >= nextCost && !isMaxed;
const elBtn = document.getElementById(`btn-perk-${perk.id}`);
if (elBtn) elBtn.disabled = !canAfford;
}
}