feat(meal-plan): add servings field to MealPlanEntry and update related functionality
feat(products): implement bulk update for product categories feat(recipes): add servings input to WriteRecipePage and update MealPlanClient for servings management refactor(types): enhance Product and Category types with additional properties
This commit is contained in:
@@ -9,7 +9,9 @@ const DAYS_SV = ['Måndag', 'Tisdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lördag',
|
||||
type MealPlanEntry = {
|
||||
id: number;
|
||||
date: string;
|
||||
servings: number | null;
|
||||
recipe: Pick<Recipe, 'id' | 'name' | 'imageUrl'> & {
|
||||
servings: number | null;
|
||||
ingredients: { quantity: string; unit: string; note: string | null; product: { id: number; name: string; canonicalName: string | null } }[];
|
||||
};
|
||||
};
|
||||
@@ -89,10 +91,11 @@ export default function MealPlanClient({ recipes }: { recipes: Recipe[] }) {
|
||||
if (!recipeId) {
|
||||
await fetch(`/api/meal-plan-proxy?date=${date}`, { method: 'DELETE' });
|
||||
} else {
|
||||
const existing = entryForDate(date);
|
||||
await fetch('/api/meal-plan-proxy', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ date, recipeId: Number(recipeId) }),
|
||||
body: JSON.stringify({ date, recipeId: Number(recipeId), servings: existing?.servings ?? null }),
|
||||
});
|
||||
}
|
||||
await load();
|
||||
@@ -103,6 +106,17 @@ export default function MealPlanClient({ recipes }: { recipes: Recipe[] }) {
|
||||
|
||||
const plannedCount = weekDates.filter((d) => entryForDate(d)).length;
|
||||
|
||||
const handleServingsChange = async (date: string, servings: number | null) => {
|
||||
const entry = entryForDate(date);
|
||||
if (!entry) return;
|
||||
await fetch('/api/meal-plan-proxy', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ date, recipeId: entry.recipe.id, servings }),
|
||||
});
|
||||
await load();
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Veckonavigering */}
|
||||
@@ -173,6 +187,29 @@ export default function MealPlanClient({ recipes }: { recipes: Recipe[] }) {
|
||||
Visa recept →
|
||||
</Link>
|
||||
)}
|
||||
{entry && entry.recipe.servings && (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.35rem', fontSize: '0.82rem', color: '#555' }}>
|
||||
<span>Port.:</span>
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
step={1}
|
||||
value={entry.servings ?? entry.recipe.servings}
|
||||
onChange={(e) => handleServingsChange(date, e.target.value ? Number(e.target.value) : null)}
|
||||
style={{ width: '52px', padding: '0.25rem 0.4rem', border: '1px solid #ced4da', borderRadius: '4px', fontSize: '0.82rem' }}
|
||||
/>
|
||||
{entry.servings && entry.servings !== entry.recipe.servings && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleServingsChange(date, null)}
|
||||
title={`Återställ till ${entry.recipe.servings} portioner`}
|
||||
style={{ fontSize: '0.75rem', color: '#888', background: 'none', border: 'none', cursor: 'pointer', padding: '0 0.2rem' }}
|
||||
>
|
||||
↩ {entry.recipe.servings}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{isSaving && <span style={{ fontSize: '0.8rem', color: '#888' }}>Sparar...</span>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user