Virtual Aquarium

Virtual Aquarium

Total Fish
0
Total Tank Value
$0

Add New Fish Type

Configured Fish Types

No fish types defined.

"; } vaConfig.fishTypes.forEach((type) => { const item = document.createElement("div"); item.className = "va-list-item"; item.innerHTML = ` ${type.name} Value: ${formatCurrency( type.value )}
`; configListContainer.appendChild(item); }); } /** * Update navigation button states. */ function updateNavButtons() { if (!nextBtn || !prevBtn) return; if (currentTabId === "va-tab-dashboard") { prevBtn.disabled = true; nextBtn.disabled = false; } else if (currentTabId === "va-tab-config") { prevBtn.disabled = false; nextBtn.disabled = true; } } /** * Re-renders all UI components. */ function fullRefreshUI() { renderDashboard(); renderConfig(); updateNavButtons(); } // === EVENT HANDLERS (Must be global for onclick) === window.vaShowTab = (tabId, element) => { // Hide all content container .querySelectorAll(".va-tab-content") .forEach((tab) => (tab.style.display = "none")); // Deactivate all links container .querySelectorAll(".va-tab-link") .forEach((link) => link.classList.remove("va-active")); // Show selected content const tabToShow = container.querySelector("#" + tabId); if (tabToShow) { tabToShow.style.display = "block"; } // Activate selected link if (element) { element.classList.add("va-active"); } currentTabId = tabId; updateNavButtons(); }; window.vaNavigateTabs = (isNext) => { const tabs = Array.from( container.querySelectorAll(".va-tab-link") ); const currentIdx = tabs.findIndex((tab) => tab.classList.contains("va-active") ); let newIdx = isNext ? currentIdx + 1 : currentIdx - 1; if (newIdx >= 0 && newIdx < tabs.length) { tabs[newIdx].click(); } }; // --- Config Tab Handlers --- window.vaAddFishType = () => { if ( !newNameInput || !newValueInput || !newShapeSelect || !newColorInput ) return; const name = newNameInput.value.trim(); const value = parseFloat(newValueInput.value); const shape = newShapeSelect.value; const color = newColorInput.value.trim(); if (!name || isNaN(value) || !shape || !color) { alert("Please fill in all fields with valid data."); return; } const newType = { id: "ft" + Date.now(), name, value, shape, color, }; vaConfig.fishTypes.push(newType); newNameInput.value = ""; newValueInput.value = ""; newColorInput.value = ""; fullRefreshUI(); }; window.vaRemoveFishType = (id) => { if ( !confirm( "Are you sure you want to remove this fish type?\nAll fish of this type will be removed from the aquarium." ) ) { return; } // Remove from config vaConfig.fishTypes = vaConfig.fishTypes.filter( (t) => t.id !== id ); // Remove instances from state vaState.myFish = vaState.myFish.filter( (f) => f.typeId !== id ); fullRefreshUI(); }; // --- Dashboard Tab Handlers --- window.vaAddFish = () => { if (!fishTypeSelect) return; const typeId = fishTypeSelect.value; if (!typeId) { alert("Please define a fish type in the Configuration tab first."); return; } const newFish = { instanceId: "i" + Date.now(), typeId: typeId, }; vaState.myFish.push(newFish); renderDashboard(); // Just re-render the dashboard }; window.vaRemoveFish = (instanceId) => { vaState.myFish = vaState.myFish.filter( (f) => f.instanceId !== instanceId ); renderDashboard(); // Re-render to remove the fish element }; // --- PDF Download --- window.vaDownloadPDF = () => { if (!jsPDF) { alert("PDF library is not loaded. Please try again."); return; } try { const doc = new jsPDF(); const pageMargin = 15; const pageWidth = doc.internal.pageSize.getWidth(); let y = 20; // 1. Title doc.setFontSize(20); doc.text( "Virtual Aquarium Inventory", pageWidth / 2, y, { align: "center" } ); y += 20; // 2. Tally the fish const inventory = {}; let grandTotalValue = 0; let grandTotalQty = 0; vaState.myFish.forEach((fish) => { const type = vaConfig.fishTypes.find( (t) => t.id === fish.typeId ); if (type) { if (!inventory[type.id]) { inventory[type.id] = { name: type.name, value: type.value, qty: 0, }; } inventory[type.id].qty++; } }); // 3. Prepare data for table const tableBody = []; const tableHead = [ "Fish Type", "Quantity", "Value (each)", "Total Value", ]; Object.values(inventory).forEach((item) => { const itemTotal = item.qty * item.value; grandTotalQty += item.qty; grandTotalValue += itemTotal; tableBody.push([ item.name, item.qty, formatCurrency(item.value), formatCurrency(itemTotal), ]); }); // 4. Add Summary Row tableBody.push([ { content: "GRAND TOTAL", styles: { fontStyle: "bold" } }, { content: grandTotalQty, styles: { fontStyle: "bold" } }, "", { content: formatCurrency(grandTotalValue), styles: { fontStyle: "bold" }, }, ]); // 5. Draw table if (grandTotalQty > 0) { doc.autoTable({ startY: y, head: [tableHead], body: tableBody, theme: "striped", headStyles: { fillColor: [0, 123, 255] }, // --va-primary-color footStyles: { fontStyle: "bold" }, }); } else { doc.setFontSize(12); doc.text( "The aquarium is currently empty.", pageWidth / 2, y, { align: "center" } ); } doc.save("Virtual_Aquarium_Inventory.pdf"); } catch (e) { console.error("Error generating PDF:", e); alert( "An error occurred while generating the PDF." ); } }; // === INITIALIZATION === fullRefreshUI(); });