/** * Inventory Rendering Module * Handles UI rendering for inventory v2 system */ import { extensionSettings, $inventoryContainer } from '../../core/state.js'; import { getInventoryRenderOptions } from '../interaction/inventoryActions.js'; // Type imports /** @typedef {import('../../types/inventory.js').InventoryV2} InventoryV2 */ /** * Renders the inventory sub-tab navigation (On Person, Stored, Assets) * @param {string} activeTab - Currently active sub-tab ('onPerson', 'stored', 'assets') * @returns {string} HTML for sub-tab navigation */ export function renderInventorySubTabs(activeTab = 'onPerson') { return `
`; } /** * Renders the "On Person" inventory view * @param {string} onPersonItems - Current on-person items * @returns {string} HTML for on-person view with edit controls */ export function renderOnPersonView(onPersonItems) { const displayText = onPersonItems || 'None'; return `

Items Currently Carried

${escapeHtml(displayText)}
`; } /** * Renders the "Stored" inventory view with collapsible locations * @param {Object.} stored - Stored items by location * @param {string[]} collapsedLocations - Array of collapsed location names * @returns {string} HTML for stored inventory with all locations */ export function renderStoredView(stored, collapsedLocations = []) { const locations = Object.keys(stored || {}); let html = `

Storage Locations

`; if (locations.length === 0) { html += `
No storage locations yet. Click "Add Location" to create one.
`; } else { for (const location of locations) { const items = stored[location]; const isCollapsed = collapsedLocations.includes(location); html += `
${escapeHtml(location)}
${escapeHtml(items || 'None')}
`; } } html += `
`; return html; } /** * Renders the "Assets" inventory view * @param {string} assets - Current assets (vehicles, property, equipment) * @returns {string} HTML for assets view with edit controls */ export function renderAssetsView(assets) { const displayText = assets || 'None'; return `

Vehicles, Property & Major Possessions

${escapeHtml(displayText)}
Assets include vehicles (cars, motorcycles), property (homes, apartments), and major equipment (workshop tools, special items).
`; } /** * Generates inventory HTML (internal helper) * @param {InventoryV2} inventory - Inventory data to render * @param {Object} options - Rendering options * @param {string} options.activeSubTab - Currently active sub-tab ('onPerson', 'stored', 'assets') * @param {string[]} options.collapsedLocations - Collapsed storage locations * @returns {string} Complete HTML for inventory tab content */ function generateInventoryHTML(inventory, options = {}) { const { activeSubTab = 'onPerson', collapsedLocations = [] } = options; // Handle legacy v1 format - convert to v2 for display let v2Inventory = inventory; if (typeof inventory === 'string') { v2Inventory = { version: 2, onPerson: inventory, stored: {}, assets: 'None' }; } // Ensure v2 structure has all required fields if (!v2Inventory || typeof v2Inventory !== 'object') { v2Inventory = { version: 2, onPerson: 'None', stored: {}, assets: 'None' }; } let html = `
${renderInventorySubTabs(activeSubTab)}
`; // Render the active view switch (activeSubTab) { case 'onPerson': html += renderOnPersonView(v2Inventory.onPerson); break; case 'stored': html += renderStoredView(v2Inventory.stored, collapsedLocations); break; case 'assets': html += renderAssetsView(v2Inventory.assets); break; default: html += renderOnPersonView(v2Inventory.onPerson); } html += `
`; return html; } /** * Updates the inventory display in the DOM (used by inventoryActions) * @param {string} containerId - ID of container element to update * @param {Object} options - Rendering options (passed to generateInventoryHTML) */ export function updateInventoryDisplay(containerId, options = {}) { const container = document.getElementById(containerId); if (!container) { console.warn(`[RPG Companion] Inventory container not found: ${containerId}`); return; } const inventory = extensionSettings.userStats.inventory; const html = generateInventoryHTML(inventory, options); container.innerHTML = html; } /** * Main inventory rendering function (matches pattern of other render functions) * Gets data from state/settings and updates DOM directly. * Call this after AI generation, character changes, or swipes. */ export function renderInventory() { // Early return if container doesn't exist or section is hidden if (!$inventoryContainer || !extensionSettings.showInventory) { return; } // Get inventory data from settings const inventory = extensionSettings.userStats.inventory; // Get current render options (active tab, collapsed locations) const options = getInventoryRenderOptions(); // Generate HTML and update DOM const html = generateInventoryHTML(inventory, options); $inventoryContainer.html(html); } /** * Escapes HTML special characters to prevent XSS * @param {string} text - Text to escape * @returns {string} Escaped text */ function escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; }