diff --git a/frontend/src/lib/planner/SwapSuggestionList.svelte b/frontend/src/lib/planner/SwapSuggestionList.svelte index 0049a93..3a928e9 100644 --- a/frontend/src/lib/planner/SwapSuggestionList.svelte +++ b/frontend/src/lib/planner/SwapSuggestionList.svelte @@ -11,6 +11,7 @@ replacingMeta, recipes, currentWeekRecipeIds, + isLoading = false, onpick, oncancel }: { @@ -18,6 +19,7 @@ replacingMeta?: string; recipes: Recipe[]; currentWeekRecipeIds: Set; + isLoading?: boolean; onpick: (recipeId: string, recipeName: string) => void; oncancel?: () => void; } = $props(); @@ -97,7 +99,8 @@ diff --git a/frontend/src/lib/planner/SwapSuggestionList.test.ts b/frontend/src/lib/planner/SwapSuggestionList.test.ts index d8b3294..bd862a1 100644 --- a/frontend/src/lib/planner/SwapSuggestionList.test.ts +++ b/frontend/src/lib/planner/SwapSuggestionList.test.ts @@ -74,6 +74,18 @@ describe('SwapSuggestionList', () => { expect(screen.getByTestId('swap-empty-state')).toBeTruthy(); }); + it('disables all Wählen buttons when isLoading is true', () => { + render(SwapSuggestionList, { props: { ...baseProps, isLoading: true } }); + const buttons = screen.getAllByRole('button', { name: /Wählen/i }); + buttons.forEach((btn) => expect((btn as HTMLButtonElement).disabled).toBe(true)); + }); + + it('Wählen buttons are enabled when isLoading is false', () => { + render(SwapSuggestionList, { props: { ...baseProps, isLoading: false } }); + const buttons = screen.getAllByRole('button', { name: /Wählen/i }); + buttons.forEach((btn) => expect((btn as HTMLButtonElement).disabled).toBe(false)); + }); + it('renders optional Abbrechen button when oncancel provided', () => { render(SwapSuggestionList, { props: { ...baseProps, oncancel: vi.fn() } }); expect(screen.getByRole('button', { name: /Abbrechen/i })).toBeTruthy(); diff --git a/frontend/src/routes/(app)/planner/+page.svelte b/frontend/src/routes/(app)/planner/+page.svelte index 5de86c8..769e219 100644 --- a/frontend/src/routes/(app)/planner/+page.svelte +++ b/frontend/src/routes/(app)/planner/+page.svelte @@ -61,6 +61,7 @@ let pickerOpen = $state(false); let actionSheetOpen = $state(false); let swapSheetOpen = $state(false); + let swapLoading = $state(false); // Recipes already in any slot this week — used for ⚠ overlap warnings let currentWeekRecipeIds = $derived( @@ -139,8 +140,10 @@ } async function handleSwapPick(recipeId: string, recipeName: string) { - swapSheetOpen = false; + swapLoading = true; await handleRecipePick(recipeId, recipeName); + swapSheetOpen = false; + swapLoading = false; } function closePanelToIdle() { @@ -306,6 +309,7 @@ replacingMeta={replacingMeta || undefined} recipes={sortedRecipes} {currentWeekRecipeIds} + isLoading={swapLoading} onpick={handleSwapPick} oncancel={() => (swapSheetOpen = false)} />