feat(planner): add remove meal with undo; fix RecipePicker badge for neutral delta

- MealActionSheet: new onremove prop + Entfernen button (guarded by #if)
- +page.svelte: handleRemoveMeal submits delete form, shows undo bar;
  undo re-adds via addSlot form; refactored handleUndo to undoCallback
  pattern; desktop day-detail panel also gets Entfernen button
- RecipePicker: only show green +delta badge when scoreDelta > 0;
  neutral (scoreDelta = 0) shows no badge instead of ⚠ Variationskonflikt
- Tests: page.test.ts remove-meal describe, RecipePicker neutral badge test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-09 12:47:53 +02:00
parent 77cdccb26c
commit 1de9dfc314
4 changed files with 96 additions and 6 deletions

View File

@@ -104,7 +104,7 @@
{meta}
</p>
{/if}
{#if !suggestion.hasConflict}
{#if (suggestion.scoreDelta ?? 0) > 0}
<span
data-testid="badge-{suggestion.recipe.id}"
data-type="good"
@@ -112,7 +112,7 @@
>
↑ +{(suggestion.scoreDelta ?? 0).toFixed(1)} Punkte
</span>
{:else}
{:else if suggestion.hasConflict}
<span
data-testid="badge-{suggestion.recipe.id}"
data-type="warning"

View File

@@ -98,6 +98,14 @@ describe('RecipePicker', () => {
expect(screen.getByText(/Keine Treffer/i)).toBeTruthy();
});
it('shows no badge when scoreDelta is zero (neutral, no improvement)', () => {
const neutralSuggestions = [
{ recipe: { id: 'sn', name: 'Neutrales Rezept', effort: 'easy', cookTimeMin: 20 }, scoreDelta: 0.0, hasConflict: false }
];
render(RecipePicker, { props: { ...baseProps, suggestions: neutralSuggestions } });
expect(screen.queryByTestId('badge-sn')).toBeNull();
});
it('shows loading skeleton instead of Empfohlen section when isLoading is true', () => {
render(RecipePicker, { props: { ...baseProps, isLoading: true } });
expect(screen.getByTestId('suggestions-loading')).toBeTruthy();