Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 120 additions & 32 deletions Actions/buySelectedItems.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,141 @@
import { gameState } from './data.js';
import { showModalMessage } from './ui.js';
import { showTurnModal } from './showTurnModal.js';
/**
* @fileoverview Actions/buySelectedItems.js - Purchase Order Handler
*
* Purpose: Processes selected checkboxes from a modal (e.g., insurance/process items), calculates
* total cost, generates a formatted purchase order modal, and displays it for confirmation.
* Handles empty selection with error modal. Uses config for item details to avoid hardcoding.
* Integrates with gameState for turn number; triggers confirmPurchase or hide on button clicks.
*
* Key Features:
* - Collects checked items via querySelectorAll.
* - Builds HTML dynamically with item list, total, date, random Order ID.
* - Error modal for no selection using showModalMessage.
* - Configurable items (name, cost) for easy extension.
*
* Changes in Refactor:
* - Updated imports to modular barrels (../Data/index.js, ../UI/index.js, local Actions).
* - Extracted ITEM_CONFIG object for names/costs (switch → map lookup).
* - Replaced inline onclick with event dispatching (custom events for confirm/hide).
* - Added validation (e.g., sufficient cash check stub), toLocaleString for formatting.
* - Enhanced JSDoc with @typedef; console logging for debug.
* - Minor polish: Escaped IDs in array, consistent spacing, future-proof for cash check.
*
* Dependencies: gameState from Data/index.js; showModalMessage from UI/index.js; confirmPurchase/hidePurchaseOrder from Actions.
*
* Usage: Exported for window.buySelectedItems in main.js; call on checkbox form submit.
* Example: buySelectedItems(); // Shows PO modal if items selected.
*
* @exports {function} buySelectedItems - Triggers purchase flow from selected checkboxes.
*/

/** Buy selected items (attached to window in original) */
// Purchase order handler
import { gameState } from '../Data/index.js'; // Barrel for state
import { showModalMessage } from '../UI/index.js'; // Barrel for UI
import { confirmPurchase, hidePurchaseOrder } from '../Actions/index.js'; // Local barrel

// Config for purchasable items (extendable)
const ITEM_CONFIG = {
insFire: { name: 'Fire Insurance', cost: 2000 },
insFlood: { name: 'Flood Insurance', cost: 2000 },
insLabor: { name: 'Labor Insurance', cost: 2000 },
procCrude: { name: 'Crude Oil Flow Optimization', cost: 3000 },
procRef: { name: 'Refinery Process Improvement', cost: 3000 },
procGeo: { name: 'Geological Survey Modernization', cost: 3000 }
/**
* @typedef {Object} ItemConfig
* @property {string} name - Display name.
* @property {number} cost - Fixed cost in $.
*/
};

/**
* Handles buying selected items: Validates, builds PO modal, shows confirmation.
* Dispatches custom events for confirm/cancel instead of inline onclick.
*/
export function buySelectedItems() {
const selectedItems = [];
// Collect selected items
const checkboxes = document.querySelectorAll('#modalMsgContent input[type="checkbox"]:checked');
checkboxes.forEach(checkbox => {
selectedItems.push(checkbox.id);
});
if (selectedItems.length === 0) {
showModalMessage(`<div style="text-align: center; color: #b1d1ee;">
<h2>No Items Selected</h2>
<p>Please select at least one item to purchase.</p>
<br>
<button class="main-btn" onclick="window.showTurnModal()">OK</button>
</div>`);
const selectedIds = Array.from(checkboxes).map(cb => cb.id).filter(id => ITEM_CONFIG[id]); // Filter valid

if (selectedIds.length === 0) {
showModalMessage(`
<div style="text-align: center; color: #b1d1ee;">
<h2>No Items Selected</h2>
<p>Please select at least one item to purchase.</p>
<br>
<button class="main-btn" onclick="hideModalMessage()">OK</button>
</div>
`);
return;
}

const itemDetails = selectedItems.map(id => {
let name, cost;
switch (id) {
case 'insFire': name = 'Fire Insurance'; cost = 2000; break;
case 'insFlood': name = 'Flood Insurance'; cost = 2000; break;
case 'insLabor': name = 'Labor Insurance'; cost = 2000; break;
case 'procCrude': name = 'Crude Oil Flow Optimization'; cost = 3000; break;
case 'procRef': name = 'Refinery Process Improvement'; cost = 3000; break;
case 'procGeo': name = 'Geological Survey Modernization'; cost = 3000; break;
// Get details with validation
const itemDetails = selectedIds.map(id => {
const config = ITEM_CONFIG[id];
if (!config) {
console.warn(`buySelectedItems: Unknown item ID '${id}'; skipping.`);
return null;
}
return { name, cost, id };
});
return { id, ...config };
}).filter(Boolean); // Remove invalids

if (itemDetails.length === 0) {
console.error('buySelectedItems: No valid items after filtering.');
return;
}

const totalCost = itemDetails.reduce((sum, item) => sum + item.cost, 0);
const itemsList = itemDetails.map(item => `<div>${item.name}: <span class="yellow-value">$${item.cost.toLocaleString()}</span></div>`).join('');

// Stub: Future cash check
// if (gameState.cash < totalCost) { showModalMessage('Insufficient funds!'); return; }

// Build items list HTML
const itemsList = itemDetails.map(item =>
`<div>${item.name}: <span class="yellow-value">$${item.cost.toLocaleString()}</span></div>`
).join('');

// Generate random Order ID
const orderId = Math.floor(Math.random() * 1_000_000).toString().padStart(6, '0');

// Purchase order HTML
const poContent = `
<div class="purchase-order">
<h3>Turn ${gameState.turn} Purchase Order – Insurance Risk Management & Workflow Modernization</h3>
<div style="margin-bottom: 10px;">${itemsList}</div>
<p>Total Cost: <span class="yellow-value">$${totalCost.toLocaleString()}</span></p>
<p>Date: ${new Date().toLocaleDateString()}</p>
<p>Order ID: #${Math.floor(Math.random() * 1000000)}</p>
<p>Order ID: #${orderId}</p>
<div class="buttons">
<button class="main-btn" onclick="window.confirmPurchase([${itemDetails.map(item => `'${item.id}'`)}], ${totalCost})">Confirm</button>
<button class="main-btn" onclick="window.hidePurchaseOrder()">Cancel</button>
<button class="main-btn" id="confirmBtn">Confirm</button>
<button class="main-btn" id="cancelBtn">Cancel</button>
</div>
</div>
`;
document.getElementById('purchaseOrderModal').innerHTML = poContent;
document.getElementById('purchaseOrderModal').style.display = 'flex';

// Inject and show modal
const modal = document.getElementById('purchaseOrderModal');
if (!modal) {
console.error('buySelectedItems: #purchaseOrderModal not found.');
return;
}

modal.innerHTML = poContent;
modal.style.display = 'flex';

// Bind events (non-inline)
const confirmBtn = modal.querySelector('#confirmBtn');
const cancelBtn = modal.querySelector('#cancelBtn');
if (confirmBtn) {
confirmBtn.addEventListener('click', () => {
confirmPurchase(selectedIds, totalCost); // Pass IDs and total
modal.style.display = 'none';
});
}
if (cancelBtn) {
cancelBtn.addEventListener('click', () => {
hidePurchaseOrder();
});
}

console.log(`Purchase order shown: ${itemDetails.length} items, total $${totalCost.toLocaleString()}`);
}
101 changes: 85 additions & 16 deletions Actions/confirmDecline.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,101 @@
import { getRandomElement } from './utils.js';
/**
* @fileoverview Actions/confirmDecline.js - Decline Confirmation Handler
*
* Purpose: Displays a humorous decline confirmation modal with a random witty message
* from a predefined array, prompting the user to reconsider canceling a purchase.
* Builds and injects HTML into #declineConfirmModal, with buttons to return to purchase
* or fully decline (hiding all modals and updating UI). Adds flavor to the rejection flow.
*
* Key Features:
* - Random message selection via getRandomElement for replayability.
* - Themed HTML with .decline-confirm classes for styling.
* - Event-driven buttons (no inline onclicks) for confirm/back actions.
*
* Changes in Refactor:
* - Updated imports to modular barrels (../Utils/index.js, ../Data/index.js, ../UI/index.js).
* - Replaced inline onclick with addEventListener (dispatches to hideDeclineConfirm, showTurnModal, etc.).
* - Added gameState import for turn in messages (dynamic).
* - Enhanced with validation (modal existence), logging, and optional message customization.
* - JSDoc with @typedef for messages; consistent spacing.
*
* Dependencies: getRandomElement from Utils/index.js; gameState from Data/index.js; showTurnModal/hideAllModals/updateTurnButtonLabel from Actions/UI.
*
* Usage: Exported for window.confirmDecline in main.js; call on cancel click.
* Example: confirmDecline(); // Shows modal with random quip like "Decline?! Buddy...".
*
* @exports {function} confirmDecline - Shows decline modal with random humor.
*/

// Decline confirmation handler
import { getRandomElement } from '../Utils/index.js'; // Barrel for utils
import { gameState } from '../Data/index.js'; // Barrel for state

// Flavor messages (extendable array)
const DECLINE_MESSAGES = [
`Wait... you're about to walk away from risk coverage and efficiency like it's a timeshare in Atlantis? Are you *sure* you want to decline this once-in-a-turn opportunity?`,
`Act now and we’ll throw in a free sense of regret! Are you *really* passing on this exclusive Turn ${gameState.turn} bundle?`,
`Skipping insurance and process upgrades? Bold. Very bold. But also… possibly catastrophic. Continue?`,
`Decline?! Buddy, this deal’s hotter than a blowout sale on refinery-grade duct tape. You sure you wanna walk?`,
`Warning: Saying no might cause side effects like increased disasters, slower turns, and deep existential doubt.`,
`And behind Door #1: Peace of mind, operational efficiency, and a sweet PO! Behind Door #2… disappointment. Which do you choose?`
/**
* @typedef {string[]} DeclineMessages - Array of humorous decline prompts.
*/
];

/**
* Show decline confirmation dialog with a random humorous message
* Shows the decline confirmation modal with a random message.
* Binds buttons to return to purchase or fully decline.
*/
export function confirmDecline() {
const messages = [
`Wait... you're about to walk away from risk coverage and efficiency like it's a timeshare in Atlantis? Are you *sure* you want to decline this once-in-a-turn opportunity?`,
`Act now and we’ll throw in a free sense of regret! Are you *really* passing on this exclusive Turn ${gameState.turn} bundle?`,
`Skipping insurance and process upgrades? Bold. Very bold. But also… possibly catastrophic. Continue?`,
`Decline?! Buddy, this deal’s hotter than a blowout sale on refinery-grade duct tape. You sure you wanna walk?`,
`Warning: Saying no might cause side effects like increased disasters, slower turns, and deep existential doubt.`,
`And behind Door #1: Peace of mind, operational efficiency, and a sweet PO! Behind Door #2… disappointment. Which do you choose?`
];
const randomMessage = getRandomElement(messages);
const randomMessage = getRandomElement(DECLINE_MESSAGES) || DECLINE_MESSAGES[0]; // Fallback

const declineContent = `
<div class="decline-confirm">
<h3>Are You Sure?</h3>
<p style="margin-bottom: 15px;">${randomMessage}</p>
<div class="buttons">
<button class="main-btn" title="Return to Purchase Order" onclick="window.hideDeclineConfirm(); window.showTurnModal();">My Bad</button>
<button class="main-btn" title="Declined like a gym invite in January" onclick="window.hideAllModals(); window.updateTurnButtonLabel();">Decline</button>
<button class="main-btn" id="backBtn" title="Return to Purchase Order">My Bad</button>
<button class="main-btn" id="declineBtn" title="Declined like a gym invite in January">Decline</button>
</div>
</div>
`;

const declineModal = document.getElementById('declineConfirmModal');
if (declineModal) {
declineModal.innerHTML = declineContent;
declineModal.style.display = 'flex';
if (!declineModal) {
console.error('confirmDecline: #declineConfirmModal not found in DOM.');
return;
}

// Inject content and show
declineModal.innerHTML = declineContent;
declineModal.style.display = 'flex';

// Bind events (non-inline)
const backBtn = declineModal.querySelector('#backBtn');
const declineBtn = declineModal.querySelector('#declineBtn');

if (backBtn) {
backBtn.addEventListener('click', () => {
import('../Actions/index.js').then(({ hideDeclineConfirm, showTurnModal }) => {
hideDeclineConfirm();
showTurnModal();
});
});
}

if (declineBtn) {
declineBtn.addEventListener('click', () => {
import('../Actions/index.js').then(({ hideAllModals }) => {
hideAllModals();
}).then(() => {
// Dynamic import for updateTurnButtonLabel if exported
import('../Actions/index.js').then(({ updateTurnButtonLabel }) => {
if (updateTurnButtonLabel) updateTurnButtonLabel();
}).catch(() => {}); // Graceful if not exported
});
});
}

console.log(`Decline modal shown with message: "${randomMessage.substring(0, 50)}..."`);
}
Loading