feat(planner): add isLoading prop to SwapSuggestionList — disables Pick buttons during PATCH

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-09 10:32:59 +02:00
parent 9482ecbf36
commit b4fa3ca23e
3 changed files with 21 additions and 2 deletions

View File

@@ -11,6 +11,7 @@
replacingMeta,
recipes,
currentWeekRecipeIds,
isLoading = false,
onpick,
oncancel
}: {
@@ -18,6 +19,7 @@
replacingMeta?: string;
recipes: Recipe[];
currentWeekRecipeIds: Set<string>;
isLoading?: boolean;
onpick: (recipeId: string, recipeName: string) => void;
oncancel?: () => void;
} = $props();
@@ -97,7 +99,8 @@
<button
type="button"
onclick={() => onpick(recipe.id, recipe.name)}
style="background: none; border: none; cursor: pointer; font-size: 11px; font-weight: 500; color: var(--green); font-family: var(--font-sans); flex-shrink: 0;"
disabled={isLoading}
style="background: none; border: none; cursor: {isLoading ? 'default' : 'pointer'}; font-size: 11px; font-weight: 500; color: var(--green); font-family: var(--font-sans); flex-shrink: 0; opacity: {isLoading ? '0.4' : '1'};"
>
Wählen
</button>

View File

@@ -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();

View File

@@ -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)}
/>