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();
});