feat(ui): two render states — hero vs results — with unified padding
Hero state (no senderId): centred CorrespondenzHero with discovery headline, cross-link, large typeahead, recent persons. No person bar or filter controls shown. Results state (senderId set): full-width strips then content area with max-w-7xl responsive padding matching other overview pages. Removes focus delegation hack. Refs: #179 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -53,17 +53,29 @@ const withDocs = {
|
||||
documents: [makeDoc()]
|
||||
};
|
||||
|
||||
// ─── Empty state (no senderId) ────────────────────────────────────────────────
|
||||
// ─── Hero state (no senderId) ────────────────────────────────────────────────
|
||||
|
||||
describe('Korrespondenz page – empty state', () => {
|
||||
it('shows the search heading when no person is selected', async () => {
|
||||
describe('Briefwechsel page – hero state', () => {
|
||||
it('shows the hero when no person is selected', async () => {
|
||||
render(Page, { data: baseData });
|
||||
await expect.element(page.getByText(/Korrespondenz durchsuchen/i)).toBeInTheDocument();
|
||||
await expect.element(page.getByTestId('conv-hero')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the empty-search button', async () => {
|
||||
it('shows the discovery headline', async () => {
|
||||
render(Page, { data: baseData });
|
||||
await expect.element(page.getByTestId('conv-empty-search')).toBeInTheDocument();
|
||||
await expect.element(page.getByText(/Wessen Briefe möchten Sie lesen/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show the person bar in hero state', async () => {
|
||||
render(Page, { data: baseData });
|
||||
await expect.element(page.getByTestId('conv-hero')).toBeInTheDocument();
|
||||
await expect.element(page.getByTestId('conv-person-bar')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show filter controls in hero state', async () => {
|
||||
render(Page, { data: baseData });
|
||||
await expect.element(page.getByTestId('conv-hero')).toBeInTheDocument();
|
||||
await expect.element(page.getByTestId('conv-filter-controls')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show the new document link when no person is selected', async () => {
|
||||
@@ -77,9 +89,29 @@ describe('Korrespondenz page – empty state', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Results state (senderId set) ────────────────────────────────────────────
|
||||
|
||||
describe('Briefwechsel page – results state', () => {
|
||||
it('does not show the hero when senderId is set', async () => {
|
||||
render(Page, { data: withSender });
|
||||
await expect.element(page.getByTestId('conv-person-bar')).toBeInTheDocument();
|
||||
await expect.element(page.getByTestId('conv-hero')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the person bar when senderId is set', async () => {
|
||||
render(Page, { data: withSender });
|
||||
await expect.element(page.getByTestId('conv-person-bar')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows filter controls when senderId is set', async () => {
|
||||
render(Page, { data: withSender });
|
||||
await expect.element(page.getByTestId('conv-filter-controls')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Recent persons chips ─────────────────────────────────────────────────────
|
||||
|
||||
describe('Korrespondenz page – recent persons', () => {
|
||||
describe('Briefwechsel page – recent persons', () => {
|
||||
it('shows recent person chips from localStorage', async () => {
|
||||
localStorage.setItem(
|
||||
'korrespondenz_recent_persons',
|
||||
@@ -93,15 +125,14 @@ describe('Korrespondenz page – recent persons', () => {
|
||||
it('does not crash when localStorage contains corrupt JSON', async () => {
|
||||
localStorage.setItem('korrespondenz_recent_persons', '}{not valid json');
|
||||
render(Page, { data: baseData });
|
||||
// Empty state heading is still shown — no chip list crash
|
||||
await expect.element(page.getByText(/Korrespondenz durchsuchen/i)).toBeInTheDocument();
|
||||
await expect.element(page.getByText(/Wessen Briefe möchten Sie lesen/i)).toBeInTheDocument();
|
||||
localStorage.removeItem('korrespondenz_recent_persons');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Single-person hint bar ───────────────────────────────────────────────────
|
||||
|
||||
describe('Korrespondenz page – single-person hint bar', () => {
|
||||
describe('Briefwechsel page – single-person hint bar', () => {
|
||||
it('shows hint bar when only senderId is set', async () => {
|
||||
render(Page, { data: withSender });
|
||||
await expect.element(page.getByText(/Alle Briefe von Hans Müller/i)).toBeInTheDocument();
|
||||
@@ -120,13 +151,7 @@ describe('Korrespondenz page – single-person hint bar', () => {
|
||||
|
||||
// ─── Filter controls disabled state ──────────────────────────────────────────
|
||||
|
||||
describe('Korrespondenz page – filter strip Row 2 disabled state', () => {
|
||||
it('renders filter controls with aria-disabled when no senderId', async () => {
|
||||
render(Page, { data: baseData });
|
||||
const strip = document.querySelector('[aria-disabled="true"]');
|
||||
expect(strip).not.toBeNull();
|
||||
});
|
||||
|
||||
describe('Briefwechsel page – filter strip Row 2 disabled state', () => {
|
||||
it('filter controls are not aria-disabled when senderId is set', async () => {
|
||||
render(Page, { data: withSender });
|
||||
const strip = document.querySelector('[aria-disabled="false"]');
|
||||
@@ -136,7 +161,7 @@ describe('Korrespondenz page – filter strip Row 2 disabled state', () => {
|
||||
|
||||
// ─── Strip letter count ───────────────────────────────────────────────────────
|
||||
|
||||
describe('Korrespondenz page – strip letter count', () => {
|
||||
describe('Briefwechsel page – strip letter count', () => {
|
||||
it('shows 0 Briefe when senderId is set but no documents', async () => {
|
||||
render(Page, { data: withSender });
|
||||
await expect.element(page.getByTestId('conv-strip-count')).toHaveTextContent('0 Briefe');
|
||||
@@ -150,7 +175,7 @@ describe('Korrespondenz page – strip letter count', () => {
|
||||
|
||||
// ─── No results ───────────────────────────────────────────────────────────────
|
||||
|
||||
describe('Korrespondenz page – no results', () => {
|
||||
describe('Briefwechsel page – no results', () => {
|
||||
it('shows "no documents found" when a person is selected but there are no documents', async () => {
|
||||
render(Page, { data: withSender });
|
||||
await expect.element(page.getByText(/Keine Dokumente gefunden/i)).toBeInTheDocument();
|
||||
@@ -159,12 +184,11 @@ describe('Korrespondenz page – no results', () => {
|
||||
|
||||
// ─── Swap button ──────────────────────────────────────────────────────────────
|
||||
|
||||
describe('Korrespondenz page – swap button', () => {
|
||||
describe('Briefwechsel page – swap button', () => {
|
||||
it('swap button is invisible when only one person is set', async () => {
|
||||
render(Page, { data: withSender });
|
||||
const btn = document.querySelector<HTMLElement>('[data-testid="conv-swap-btn"]');
|
||||
expect(btn).not.toBeNull();
|
||||
// opacity-0 is applied via class when swapVisible is false
|
||||
expect(btn!.className).toMatch(/opacity-0/);
|
||||
});
|
||||
|
||||
@@ -187,7 +211,7 @@ describe('Korrespondenz page – swap button', () => {
|
||||
|
||||
// ─── Year dividers ────────────────────────────────────────────────────────────
|
||||
|
||||
describe('Korrespondenz page – year dividers', () => {
|
||||
describe('Briefwechsel page – year dividers', () => {
|
||||
it('renders a year divider for the first document', async () => {
|
||||
render(Page, { data: withDocs });
|
||||
await expect.element(page.getByTestId('year-divider').first()).toHaveTextContent('1923');
|
||||
@@ -222,7 +246,7 @@ describe('Korrespondenz page – year dividers', () => {
|
||||
|
||||
// ─── New document link ────────────────────────────────────────────────────────
|
||||
|
||||
describe('Korrespondenz page – new document link', () => {
|
||||
describe('Briefwechsel page – new document link', () => {
|
||||
it('shows the link with correct href for a write user (bilateral)', async () => {
|
||||
render(Page, { data: { ...withDocs, canWrite: true } });
|
||||
const link = page.getByTestId('conv-new-doc-link');
|
||||
|
||||
Reference in New Issue
Block a user