68 lines
1.8 KiB
JavaScript
68 lines
1.8 KiB
JavaScript
const form = document.getElementById('recipe-form');
|
|
const recipesEl = document.getElementById('recipes');
|
|
const statusEl = document.getElementById('status');
|
|
|
|
async function loadRecipes() {
|
|
statusEl.textContent = 'Loading recipes...';
|
|
const res = await fetch('/api/recipes');
|
|
const recipes = await res.json();
|
|
|
|
if (!Array.isArray(recipes) || recipes.length === 0) {
|
|
recipesEl.innerHTML = '';
|
|
statusEl.textContent = 'No recipes yet. Add your first recipe above.';
|
|
return;
|
|
}
|
|
|
|
statusEl.textContent = `${recipes.length} recipe(s)`;
|
|
recipesEl.innerHTML = recipes
|
|
.map(
|
|
(recipe) => `
|
|
<article class="recipe-card">
|
|
<h3>${escapeHtml(recipe.name)}</h3>
|
|
<strong>Ingredients:</strong>
|
|
<ul>${recipe.ingredients.map((i) => `<li>${escapeHtml(i)}</li>`).join('')}</ul>
|
|
<strong>Instructions:</strong>
|
|
<p>${escapeHtml(recipe.instructions)}</p>
|
|
</article>
|
|
`
|
|
)
|
|
.join('');
|
|
}
|
|
|
|
form.addEventListener('submit', async (event) => {
|
|
event.preventDefault();
|
|
|
|
const name = document.getElementById('name').value.trim();
|
|
const ingredients = document
|
|
.getElementById('ingredients')
|
|
.value.split('\n')
|
|
.map((x) => x.trim())
|
|
.filter(Boolean);
|
|
const instructions = document.getElementById('instructions').value.trim();
|
|
|
|
const res = await fetch('/api/recipes', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ name, ingredients, instructions })
|
|
});
|
|
|
|
if (!res.ok) {
|
|
statusEl.textContent = 'Failed to save recipe. Please check your input.';
|
|
return;
|
|
}
|
|
|
|
form.reset();
|
|
await loadRecipes();
|
|
});
|
|
|
|
function escapeHtml(value) {
|
|
return String(value)
|
|
.replace(/&/g, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.replace(/\"/g, '"')
|
|
.replace(/'/g, ''');
|
|
}
|
|
|
|
loadRecipes();
|