refactor(person): move sort button into each section heading, sort independently
Some checks are pending
CI / Unit & Component Tests (push) Successful in 1m43s
CI / Backend Unit Tests (push) Successful in 1m57s
CI / E2E Tests (push) Has started running

Replaced the single shared sort control with per-section sort buttons placed
inline in each heading row (right-aligned via ml-auto). Each section now sorts
independently, which matches user expectation and keeps the control visually
anchored to the list it affects.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-03-20 11:22:56 +01:00
parent 3f717e3266
commit 931a8dac95
2 changed files with 44 additions and 25 deletions

View File

@@ -96,21 +96,36 @@ test.describe('New person', () => {
}); });
test.describe('Person detail — sort toggle', () => { test.describe('Person detail — sort toggle', () => {
test('sort toggle changes the button label when person has documents', async ({ page }) => { test('each section has its own sort toggle that works independently', async ({ page }) => {
await page.goto('/persons'); await page.goto('/persons');
const firstPerson = page.locator('a[href^="/persons/"]').first(); const firstPerson = page.locator('a[href^="/persons/"]').first();
await firstPerson.click(); await firstPerson.click();
await page.waitForSelector('[data-hydrated]'); await page.waitForSelector('[data-hydrated]');
const sortBtn = page.getByRole('button', { name: /Neueste zuerst|Älteste zuerst/i }); // Find sort buttons — there may be 0, 1 or 2 depending on whether sections have >1 doc
if (await sortBtn.isVisible()) { const sortBtns = page.getByRole('button', { name: /Neueste zuerst|Älteste zuerst/i });
await expect(sortBtn).toContainText('Neueste zuerst'); const btnCount = await sortBtns.count();
await sortBtn.click();
await expect(sortBtn).toContainText('Älteste zuerst'); if (btnCount >= 1) {
await sortBtn.click(); const firstBtn = sortBtns.first();
await expect(sortBtn).toContainText('Neueste zuerst'); await expect(firstBtn).toContainText('Neueste zuerst');
await page.screenshot({ path: 'test-results/e2e/person-sort-toggle.png' }); await firstBtn.click();
await expect(firstBtn).toContainText('Älteste zuerst');
await firstBtn.click();
await expect(firstBtn).toContainText('Neueste zuerst');
} }
if (btnCount >= 2) {
// Second sort button toggles independently
const secondBtn = sortBtns.nth(1);
await expect(secondBtn).toContainText('Neueste zuerst');
await secondBtn.click();
await expect(secondBtn).toContainText('Älteste zuerst');
// First button should be unaffected
await expect(sortBtns.first()).toContainText('Neueste zuerst');
}
await page.screenshot({ path: 'test-results/e2e/person-sort-toggle.png' });
}); });
}); });

View File

@@ -12,12 +12,13 @@
const DOCS_PREVIEW_LIMIT = 5; const DOCS_PREVIEW_LIMIT = 5;
let sortDir = $state<SortDir>('DESC'); let sortDirSent = $state<SortDir>('DESC');
let sortDirReceived = $state<SortDir>('DESC');
let showAllSent = $state(false); let showAllSent = $state(false);
let showAllReceived = $state(false); let showAllReceived = $state(false);
const sortedSentDocuments = $derived(sortDocumentsByDate(sentDocuments, sortDir)); const sortedSentDocuments = $derived(sortDocumentsByDate(sentDocuments, sortDirSent));
const sortedReceivedDocuments = $derived(sortDocumentsByDate(receivedDocuments, sortDir)); const sortedReceivedDocuments = $derived(sortDocumentsByDate(receivedDocuments, sortDirReceived));
const visibleSentDocuments = $derived(showAllSent ? sortedSentDocuments : sortedSentDocuments.slice(0, DOCS_PREVIEW_LIMIT)); const visibleSentDocuments = $derived(showAllSent ? sortedSentDocuments : sortedSentDocuments.slice(0, DOCS_PREVIEW_LIMIT));
const visibleReceivedDocuments = $derived(showAllReceived ? sortedReceivedDocuments : sortedReceivedDocuments.slice(0, DOCS_PREVIEW_LIMIT)); const visibleReceivedDocuments = $derived(showAllReceived ? sortedReceivedDocuments : sortedReceivedDocuments.slice(0, DOCS_PREVIEW_LIMIT));
@@ -330,19 +331,6 @@
</div> </div>
{/if} {/if}
<!-- Sort control -->
{#if allDocuments.length > 0}
<div class="flex justify-end mb-4">
<button
onclick={() => (sortDir = sortDir === 'DESC' ? 'ASC' : 'DESC')}
class="text-xs font-bold uppercase tracking-widest text-gray-400 hover:text-brand-navy transition-colors"
aria-label={m.conv_sort_label()}
>
{sortDir === 'DESC' ? m.conv_sort_newest() : m.conv_sort_oldest()}
</button>
</div>
{/if}
<!-- Sent Documents Section --> <!-- Sent Documents Section -->
<div class="mb-10"> <div class="mb-10">
<div class="flex items-center gap-3 mb-6 border-b border-brand-navy/10 pb-2"> <div class="flex items-center gap-3 mb-6 border-b border-brand-navy/10 pb-2">
@@ -353,6 +341,14 @@
{#if sentYearRange} {#if sentYearRange}
<span class="text-xs font-sans text-gray-400">{sentYearRange}</span> <span class="text-xs font-sans text-gray-400">{sentYearRange}</span>
{/if} {/if}
{#if sentDocuments.length > 1}
<button
onclick={() => (sortDirSent = sortDirSent === 'DESC' ? 'ASC' : 'DESC')}
class="ml-auto text-xs font-bold uppercase tracking-widest text-gray-400 hover:text-brand-navy transition-colors"
>
{sortDirSent === 'DESC' ? m.conv_sort_newest() : m.conv_sort_oldest()}
</button>
{/if}
</div> </div>
{#if sentDocuments.length === 0} {#if sentDocuments.length === 0}
@@ -417,6 +413,14 @@
{#if receivedYearRange} {#if receivedYearRange}
<span class="text-xs font-sans text-gray-400">{receivedYearRange}</span> <span class="text-xs font-sans text-gray-400">{receivedYearRange}</span>
{/if} {/if}
{#if receivedDocuments.length > 1}
<button
onclick={() => (sortDirReceived = sortDirReceived === 'DESC' ? 'ASC' : 'DESC')}
class="ml-auto text-xs font-bold uppercase tracking-widest text-gray-400 hover:text-brand-navy transition-colors"
>
{sortDirReceived === 'DESC' ? m.conv_sort_newest() : m.conv_sort_oldest()}
</button>
{/if}
</div> </div>
{#if receivedDocuments.length === 0} {#if receivedDocuments.length === 0}