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('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');
const firstPerson = page.locator('a[href^="/persons/"]').first();
await firstPerson.click();
await page.waitForSelector('[data-hydrated]');
const sortBtn = page.getByRole('button', { name: /Neueste zuerst|Älteste zuerst/i });
if (await sortBtn.isVisible()) {
await expect(sortBtn).toContainText('Neueste zuerst');
await sortBtn.click();
await expect(sortBtn).toContainText('Älteste zuerst');
await sortBtn.click();
await expect(sortBtn).toContainText('Neueste zuerst');
await page.screenshot({ path: 'test-results/e2e/person-sort-toggle.png' });
// Find sort buttons — there may be 0, 1 or 2 depending on whether sections have >1 doc
const sortBtns = page.getByRole('button', { name: /Neueste zuerst|Älteste zuerst/i });
const btnCount = await sortBtns.count();
if (btnCount >= 1) {
const firstBtn = sortBtns.first();
await expect(firstBtn).toContainText('Neueste zuerst');
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;
let sortDir = $state<SortDir>('DESC');
let sortDirSent = $state<SortDir>('DESC');
let sortDirReceived = $state<SortDir>('DESC');
let showAllSent = $state(false);
let showAllReceived = $state(false);
const sortedSentDocuments = $derived(sortDocumentsByDate(sentDocuments, sortDir));
const sortedReceivedDocuments = $derived(sortDocumentsByDate(receivedDocuments, sortDir));
const sortedSentDocuments = $derived(sortDocumentsByDate(sentDocuments, sortDirSent));
const sortedReceivedDocuments = $derived(sortDocumentsByDate(receivedDocuments, sortDirReceived));
const visibleSentDocuments = $derived(showAllSent ? sortedSentDocuments : sortedSentDocuments.slice(0, DOCS_PREVIEW_LIMIT));
const visibleReceivedDocuments = $derived(showAllReceived ? sortedReceivedDocuments : sortedReceivedDocuments.slice(0, DOCS_PREVIEW_LIMIT));
@@ -330,19 +331,6 @@
</div>
{/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 -->
<div class="mb-10">
<div class="flex items-center gap-3 mb-6 border-b border-brand-navy/10 pb-2">
@@ -353,6 +341,14 @@
{#if sentYearRange}
<span class="text-xs font-sans text-gray-400">{sentYearRange}</span>
{/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>
{#if sentDocuments.length === 0}
@@ -417,6 +413,14 @@
{#if receivedYearRange}
<span class="text-xs font-sans text-gray-400">{receivedYearRange}</span>
{/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>
{#if receivedDocuments.length === 0}