const pantryForm = document.getElementById('ingredient-form');
const pantryList = document.getElementById('pantry-list');
const filterList = document.getElementById('filter-list');
const recipesList = document.getElementById('recipes-list');
const clearPantryButton = document.getElementById('clear-pantry');
const barcodeForm = document.getElementById('barcode-form');
const barcodeMessage = document.getElementById('barcode-message');
const recipeTemplate = document.getElementById('recipe-template');
const STORAGE_KEYS = {
pantry: 'pantry-tracker-pantry',
filters: 'pantry-tracker-filters',
};
const barcodeCatalog = {
'0123456789012': { name: 'eggs', unit: 'pcs' },
'1234567890123': { name: 'flour', unit: 'g' },
'2345678901234': { name: 'soy sauce', unit: 'ml' },
'3456789012345': { name: 'milk', unit: 'ml' },
'4567890123456': { name: 'rice', unit: 'g' },
'5678901234567': { name: 'butter', unit: 'g' },
'6789012345678': { name: 'sugar', unit: 'g' },
'7890123456789': { name: 'pasta', unit: 'g' },
'8901234567890': { name: 'tomato', unit: 'pcs' },
'9012345678901': { name: 'onion', unit: 'pcs' },
};
const recipes = [
{
name: 'Fried Egg on Toast',
instructions: 'Cook an egg and serve with toast. Add salt and pepper to taste.',
ingredients: [
{ name: 'eggs', quantity: 1, unit: 'pcs' },
{ name: 'flour', quantity: 30, unit: 'g' }
]
},
{
name: 'Pancakes',
instructions: 'Mix flour, milk, and eggs into batter. Fry spoonfuls until golden.',
ingredients: [
{ name: 'flour', quantity: 150, unit: 'g' },
{ name: 'eggs', quantity: 2, unit: 'pcs' },
{ name: 'milk', quantity: 200, unit: 'ml' }
]
},
{
name: 'Soy Sauce Rice',
instructions: 'Cook rice, then stir in soy sauce and optional vegetables.',
ingredients: [
{ name: 'rice', quantity: 200, unit: 'g' },
{ name: 'soy sauce', quantity: 20, unit: 'ml' }
]
},
{
name: 'Tomato Pasta',
instructions: 'Cook pasta and toss with chopped tomato and butter.',
ingredients: [
{ name: 'pasta', quantity: 120, unit: 'g' },
{ name: 'tomato', quantity: 2, unit: 'pcs' },
{ name: 'butter', quantity: 20, unit: 'g' }
]
},
{
name: 'Omelette',
instructions: 'Whisk eggs, cook gently, and fold in butter.',
ingredients: [
{ name: 'eggs', quantity: 3, unit: 'pcs' },
{ name: 'butter', quantity: 15, unit: 'g' }
]
}
];
function loadPantry() {
const raw = localStorage.getItem(STORAGE_KEYS.pantry);
return raw ? JSON.parse(raw) : {};
}
function savePantry(pantry) {
localStorage.setItem(STORAGE_KEYS.pantry, JSON.stringify(pantry));
}
function loadFilters() {
const raw = localStorage.getItem(STORAGE_KEYS.filters);
return raw ? JSON.parse(raw) : {};
}
function saveFilters(filters) {
localStorage.setItem(STORAGE_KEYS.filters, JSON.stringify(filters));
}
function normalizeName(name) {
return name.trim().toLowerCase();
}
function updatePantryList() {
const pantry = loadPantry();
pantryList.innerHTML = '';
const keys = Object.keys(pantry).sort();
if (keys.length === 0) {
pantryList.innerHTML = '
Your pantry is empty. Add ingredients or scan a barcode.
';
return;
}
keys.forEach((key) => {
const item = pantry[key];
const card = document.createElement('div');
card.className = 'pantry-item';
const info = document.createElement('div');
info.className = 'pantry-item-info';
info.innerHTML = `${item.name}${item.quantity} ${item.unit}`;
const actions = document.createElement('div');
actions.innerHTML = ``;
card.append(info, actions);
pantryList.append(card);
});
}
function updateFilterList() {
const pantry = loadPantry();
const filters = loadFilters();
filterList.innerHTML = '';
const keys = Object.keys(pantry).sort();
if (keys.length === 0) {
filterList.innerHTML = 'Add pantry items first to filter recipes.
';
return;
}
keys.forEach((key) => {
const item = pantry[key];
const id = `filter-${key}`;
const row = document.createElement('div');
row.className = 'filter-item';
row.innerHTML = `
${item.quantity} ${item.unit} available
`;
filterList.append(row);
});
}
function canMakeRecipe(recipe, pantry, filters) {
const missing = [];
for (const required of recipe.ingredients) {
const pantryItem = pantry[normalizeName(required.name)];
if (!pantryItem) {
missing.push(required.name);
continue;
}
if (filters[pantryItem.name] === false) {
missing.push(`${required.name} (excluded)`);
continue;
}
if (pantryItem.unit !== required.unit || pantryItem.quantity < required.quantity) {
missing.push(required.name);
}
}
return { canMake: missing.length === 0, missing };
}
function updateRecipes() {
const pantry = loadPantry();
const filters = loadFilters();
recipesList.innerHTML = '';
recipes.forEach((recipe) => {
const { canMake, missing } = canMakeRecipe(recipe, pantry, filters);
const clone = recipeTemplate.content.cloneNode(true);
const card = clone.querySelector('article');
const name = clone.querySelector('.recipe-name');
const status = clone.querySelector('.recipe-status');
const ingredientList = clone.querySelector('.recipe-ingredients');
const instructions = clone.querySelector('.recipe-instructions');
const button = clone.querySelector('.use-recipe');
name.textContent = recipe.name;
status.textContent = canMake ? 'Ready to make with current pantry.' : `Missing: ${missing.join(', ')}`;
instructions.textContent = recipe.instructions;
recipe.ingredients.forEach((item) => {
const li = document.createElement('li');
li.textContent = `${item.name}: ${item.quantity} ${item.unit}`;
ingredientList.append(li);
});
button.disabled = !canMake;
button.addEventListener('click', () => handleUseRecipe(recipe));
recipesList.append(clone);
});
}
function handleUseRecipe(recipe) {
const pantry = loadPantry();
recipe.ingredients.forEach((item) => {
const key = normalizeName(item.name);
const pantryItem = pantry[key];
if (!pantryItem) return;
pantryItem.quantity = Math.max(0, pantryItem.quantity - item.quantity);
if (pantryItem.quantity === 0) {
delete pantry[key];
}
});
savePantry(pantry);
updatePantryList();
updateFilterList();
updateRecipes();
}
function notifyBarcode(message, type = 'info') {
barcodeMessage.textContent = message;
barcodeMessage.style.color = type === 'error' ? '#b91c1c' : '#1d4ed8';
barcodeMessage.style.background = type === 'error' ? '#fee2e2' : '#eff6ff';
}
function addOrUpdatePantry(name, quantity, unit) {
const pantry = loadPantry();
const key = normalizeName(name);
if (!pantry[key]) {
pantry[key] = { name: key, quantity: 0, unit };
}
const item = pantry[key];
if (item.unit !== unit) {
item.unit = unit;
}
item.quantity = Math.max(0, item.quantity + quantity);
if (item.quantity === 0) {
delete pantry[key];
}
savePantry(pantry);
updatePantryList();
updateFilterList();
updateRecipes();
}
pantryForm.addEventListener('submit', (event) => {
event.preventDefault();
const name = event.target.name.value;
const quantity = Number(event.target.quantity.value);
const unit = event.target.unit.value;
addOrUpdatePantry(name, quantity, unit);
event.target.reset();
});
barcodeForm.addEventListener('submit', (event) => {
event.preventDefault();
const rawCode = event.target.barcode.value.trim();
const quantity = Number(event.target.quantity.value);
const unit = event.target.unit.value;
if (!barcodeCatalog[rawCode]) {
notifyBarcode('Barcode not recognized. Enter a known barcode or add manually.', 'error');
return;
}
const item = barcodeCatalog[rawCode];
addOrUpdatePantry(item.name, quantity, unit || item.unit);
notifyBarcode(`Added ${quantity} ${unit} of ${item.name} to your pantry.`);
event.target.reset();
});
clearPantryButton.addEventListener('click', () => {
if (!confirm('Remove all pantry items?')) {
return;
}
localStorage.removeItem(STORAGE_KEYS.pantry);
localStorage.removeItem(STORAGE_KEYS.filters);
updatePantryList();
updateFilterList();
updateRecipes();
});
filterList.addEventListener('change', (event) => {
if (event.target.matches('input[type="checkbox"]')) {
const name = event.target.dataset.name;
const filters = loadFilters();
filters[name] = event.target.checked;
saveFilters(filters);
updateRecipes();
}
});
pantryList.addEventListener('click', (event) => {
if (!event.target.matches('.remove-item')) return;
const name = event.target.dataset.name;
const pantry = loadPantry();
delete pantry[normalizeName(name)];
savePantry(pantry);
updatePantryList();
updateFilterList();
updateRecipes();
});
function initialize() {
updatePantryList();
updateFilterList();
updateRecipes();
}
initialize();