Files
foodplanner/templates/meals.html
2025-09-19 11:12:53 -07:00

187 lines
7.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- templates/meals.html -->
{% extends "base.html" %}
{% block content %}
<div class="row">
<div class="col-md-4">
<h3>Bulk Import Meals</h3>
<form action="/meals/upload" method="post" enctype="multipart/form-data">
<div class="mb-3">
<label class="form-label">CSV File</label>
<input type="file" class="form-control" name="file" accept=".csv" required>
</div>
<button type="submit" class="btn btn-secondary mb-4">Upload CSV</button>
</form>
<h3>Create New Meal</h3>
<form action="/meals/add" method="post">
<div class="mb-3">
<label class="form-label">Meal Name</label>
<input type="text" class="form-control" name="name" required>
</div>
<div class="mb-3">
<label class="form-label">Meal Type</label>
<select class="form-control" name="meal_type" required>
<option value="breakfast">Breakfast</option>
<option value="lunch">Lunch</option>
<option value="dinner">Dinner</option>
<option value="snack">Snack</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Create Meal</button>
</form>
<div class="mt-4">
<h4>Add Food to Meal</h4>
<form id="addFoodForm">
<div class="mb-3">
<label class="form-label">Select Meal</label>
<select class="form-control" id="mealSelect">
<option value="">Choose meal...</option>
{% for meal in meals %}
<option value="{{ meal.id }}">{{ meal.name }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label class="form-label">Select Food</label>
<select class="form-control" id="foodSelect">
<option value="">Choose food...</option>
{% for food in foods %}
<option value="{{ food.id }}">{{ food.name }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label class="form-label">Quantity</label>
<input type="number" step="0.1" class="form-control" id="quantity" value="1">
</div>
<button type="button" onclick="addFoodToMeal()" class="btn btn-success">Add Food</button>
</form>
</div>
</div>
<div class="col-md-8">
<h3>Meals</h3>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th><input type="checkbox" id="select-all-meals" onclick="toggleAllMeals(this)"></th>
<th>Name</th>
<th>Type</th>
<th>Food Items</th>
</tr>
</thead>
<tbody>
{% for meal in meals %}
<tr>
<td><input type="checkbox" name="selected_meals" value="{{ meal.id }}"></td>
<td>{{ meal.name }}</td>
<td>{{ meal.meal_type.title() }}</td>
<td>
{% if meal.meal_foods %}
<ul class="list-unstyled">
{% for meal_food in meal.meal_foods %}
<li>{{ meal_food.quantity }} × {{ meal_food.food.name }}</li>
{% endfor %}
</ul>
{% else %}
<em>No foods added</em>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<button class="btn btn-danger mt-3" onclick="deleteSelectedMeals()" style="margin-top: 20px !important;">
<i class="bi bi-trash"></i> Delete Selected Meals
</button>
100| </div>
</div>
<script>
function toggleAllMeals(source) {
console.log('Toggling all meals');
const checkboxes = document.querySelectorAll('input[name="selected_meals"]');
checkboxes.forEach(checkbox => checkbox.checked = source.checked);
}
async function deleteSelectedMeals() {
console.log('Delete selected meals called');
const selected = Array.from(document.querySelectorAll('input[name="selected_meals"]:checked'))
.map(checkbox => checkbox.value);
if (selected.length === 0) {
alert('Please select meals to delete');
return;
}
if (confirm(`Delete ${selected.length} selected meals?`)) {
try {
console.log('Deleting meals:', selected);
const response = await fetch('/meals/delete', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({meal_ids: selected})
});
const result = await response.json();
console.log('Delete response:', result);
if (response.ok) {
window.location.reload();
} else {
alert(`Delete failed: ${result.message || response.status}`);
}
} catch (error) {
console.error('Delete failed:', error);
alert('Delete failed: ' + error.message);
}
}
}
// Meal CSV upload handling
document.querySelector('form[action="/meals/upload"]').addEventListener('submit', async (e) => {
e.preventDefault();
const form = e.target;
const submitBtn = form.querySelector('button[type="submit"]');
const resultsDiv = document.createElement('div');
resultsDiv.className = 'alert alert-info mt-3';
form.parentNode.insertBefore(resultsDiv, form.nextSibling);
submitBtn.disabled = true;
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Uploading...';
try {
const formData = new FormData(form);
const response = await fetch('/meals/upload', {
method: 'POST',
body: formData
});
const results = await response.json();
if (results.errors?.length > 0) {
resultsDiv.className = 'alert alert-danger';
resultsDiv.innerHTML = `<strong>Errors (${results.errors.length}):</strong><br>` +
results.errors.join('<br>');
} else {
resultsDiv.className = 'alert alert-success';
resultsDiv.innerHTML = `Successfully created ${results.created} meals, updated ${results.updated}`;
}
if (results.created || results.updated) {
setTimeout(() => window.location.reload(), 2000);
}
} catch (error) {
resultsDiv.className = 'alert alert-danger';
resultsDiv.textContent = `Upload failed: ${error.message}`;
} finally {
submitBtn.disabled = false;
submitBtn.textContent = 'Upload CSV';
}
});
</script>
{% endblock %}