refactor(planner): remove C2 suggestions route, replace with callback-based DayMealCard
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,12 +16,14 @@
|
||||
slot,
|
||||
isToday = false,
|
||||
isSelected = false,
|
||||
readonly = false
|
||||
readonly = false,
|
||||
onaddrecipe
|
||||
}: {
|
||||
slot: Slot;
|
||||
isToday?: boolean;
|
||||
isSelected?: boolean;
|
||||
readonly?: boolean;
|
||||
onaddrecipe?: () => void;
|
||||
} = $props();
|
||||
|
||||
let metadata = $derived(
|
||||
@@ -64,23 +66,27 @@
|
||||
>
|
||||
Jetzt kochen
|
||||
</a>
|
||||
<a
|
||||
href="/planner/suggestions?day={slot.slotDate}"
|
||||
class="rounded-[var(--radius-md)] border border-[var(--color-border)] px-3 py-2 text-[13px] font-medium tracking-[0.04em] font-[var(--font-sans)] text-[var(--color-text)]"
|
||||
>
|
||||
Tauschen
|
||||
</a>
|
||||
{#if onaddrecipe}
|
||||
<button
|
||||
type="button"
|
||||
onclick={onaddrecipe}
|
||||
class="rounded-[var(--radius-md)] border border-[var(--color-border)] px-3 py-2 text-[13px] font-medium tracking-[0.04em] font-[var(--font-sans)] text-[var(--color-text)]"
|
||||
>
|
||||
Tauschen
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<p class="font-[var(--font-sans)] text-[14px] text-[var(--color-text-muted)]">Kein Gericht geplant</p>
|
||||
{#if !readonly}
|
||||
<a
|
||||
href="/planner/suggestions?day={slot.slotDate}"
|
||||
{#if !readonly && onaddrecipe}
|
||||
<button
|
||||
type="button"
|
||||
onclick={onaddrecipe}
|
||||
class="mt-2 inline-block rounded-[var(--radius-md)] border border-dashed border-[var(--color-border)] px-3 py-2 text-[13px] font-medium tracking-[0.04em] font-[var(--font-sans)] text-[var(--color-text-muted)]"
|
||||
>
|
||||
+ Gericht hinzufügen
|
||||
</a>
|
||||
</button>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render, screen } from '@testing-library/svelte';
|
||||
import { userEvent } from '@testing-library/user-event';
|
||||
import DayMealCard from './DayMealCard.svelte';
|
||||
|
||||
const slot = {
|
||||
@@ -14,22 +15,29 @@ describe('DayMealCard', () => {
|
||||
expect(screen.getByText('Pasta Bolognese')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('shows Cook now and Tauschen links when not readonly', () => {
|
||||
render(DayMealCard, { props: { slot, isToday: false, readonly: false } });
|
||||
it('shows Jetzt kochen link and Tauschen button when not readonly and onaddrecipe provided', () => {
|
||||
render(DayMealCard, { props: { slot, isToday: false, readonly: false, onaddrecipe: vi.fn() } });
|
||||
expect(screen.getByRole('link', { name: /Jetzt kochen/i })).toBeTruthy();
|
||||
expect(screen.getByRole('link', { name: /Tauschen/i })).toBeTruthy();
|
||||
expect(screen.getByRole('button', { name: /Tauschen/i })).toBeTruthy();
|
||||
});
|
||||
|
||||
it('Tauschen link navigates to suggestions for the slot day', () => {
|
||||
it('Tauschen button calls onaddrecipe when clicked', async () => {
|
||||
const onaddrecipe = vi.fn();
|
||||
const user = userEvent.setup();
|
||||
render(DayMealCard, { props: { slot, isToday: false, readonly: false, onaddrecipe } });
|
||||
await user.click(screen.getByRole('button', { name: /Tauschen/i }));
|
||||
expect(onaddrecipe).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('hides Tauschen button when onaddrecipe not provided', () => {
|
||||
render(DayMealCard, { props: { slot, isToday: false, readonly: false } });
|
||||
const link = screen.getByRole('link', { name: /Tauschen/i });
|
||||
expect(link.getAttribute('href')).toContain('2026-03-30');
|
||||
expect(screen.queryByRole('button', { name: /Tauschen/i })).toBeNull();
|
||||
});
|
||||
|
||||
it('hides action links when readonly', () => {
|
||||
render(DayMealCard, { props: { slot, isToday: false, readonly: true } });
|
||||
render(DayMealCard, { props: { slot, isToday: false, readonly: true, onaddrecipe: vi.fn() } });
|
||||
expect(screen.queryByRole('link', { name: /Jetzt kochen/i })).toBeNull();
|
||||
expect(screen.queryByRole('link', { name: /Tauschen/i })).toBeNull();
|
||||
expect(screen.queryByRole('button', { name: /Tauschen/i })).toBeNull();
|
||||
});
|
||||
|
||||
it('applies today styling when isToday is true', () => {
|
||||
@@ -55,9 +63,22 @@ describe('DayMealCard', () => {
|
||||
expect(screen.getByText(/Easy/)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('empty state shows add link with suggestions href', () => {
|
||||
it('empty state shows add button when onaddrecipe provided', () => {
|
||||
const onaddrecipe = vi.fn();
|
||||
render(DayMealCard, { props: { slot: { id: 's2', slotDate: '2026-03-31', recipe: null }, isToday: false, readonly: false, onaddrecipe } });
|
||||
expect(screen.getByRole('button', { name: /Gericht hinzufügen/i })).toBeTruthy();
|
||||
});
|
||||
|
||||
it('add button calls onaddrecipe when clicked', async () => {
|
||||
const onaddrecipe = vi.fn();
|
||||
const user = userEvent.setup();
|
||||
render(DayMealCard, { props: { slot: { id: 's2', slotDate: '2026-03-31', recipe: null }, isToday: false, readonly: false, onaddrecipe } });
|
||||
await user.click(screen.getByRole('button', { name: /Gericht hinzufügen/i }));
|
||||
expect(onaddrecipe).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('empty state hides add button when onaddrecipe not provided', () => {
|
||||
render(DayMealCard, { props: { slot: { id: 's2', slotDate: '2026-03-31', recipe: null }, isToday: false, readonly: false } });
|
||||
const link = screen.getByRole('link', { name: /Gericht hinzufügen/i });
|
||||
expect(link.getAttribute('href')).toContain('2026-03-31');
|
||||
expect(screen.queryByRole('button', { name: /Gericht hinzufügen/i })).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user