From 4e67ff4258e2c336e2fa1411d221ad28fb8f76e9 Mon Sep 17 00:00:00 2001 From: Marcel Raddatz Date: Fri, 10 Apr 2026 19:54:26 +0200 Subject: [PATCH] =?UTF-8?q?feat(members):=20align=20grid=20UI=20to=20spec?= =?UTF-8?q?=20=E2=80=94=20avatar=20colors,=20badges,=20join=20date,=20invi?= =?UTF-8?q?te=20panel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MemberCard: white bg, 1px border + shadow-card, centered column layout, avatar color by role (green-dark/blue), role badge with role-specific colors, join date "seit DD.MM.YYYY", Du-badge below join date, ⋯ kebab with icons and divider, inline role-control with Abbrechen, blue editing border #B5D4F4 - InviteCard: white bg, 1.5px dashed border, min-height 180px, plus circle, label "Mitglied einladen", full hover state (green border/bg/icon/label) - InvitePanel: white bg, title "Einladelink teilen", description, mono link box, yellow expiry pill when ≤ 24h, text-link "Neuen Link generieren" - RemoveDialog: white bg, padding 28px 32px, "?" in title, updated body text - +page.server.ts: expose householdName from locals.haushalt - +page.svelte: subtitle "{n} Mitglieder · {householdName}" - Tests: add join date format test, Abbrechen test, InvitePanel title test Co-Authored-By: Claude Sonnet 4.6 --- .../src/routes/(app)/members/+page.server.ts | 3 +- .../src/routes/(app)/members/+page.svelte | 3 +- .../routes/(app)/members/InviteCard.svelte | 73 +++- .../routes/(app)/members/InvitePanel.svelte | 123 +++++- .../routes/(app)/members/InvitePanel.test.ts | 5 + .../routes/(app)/members/MemberCard.svelte | 383 +++++++++++++----- .../routes/(app)/members/MemberCard.test.ts | 28 ++ .../routes/(app)/members/RemoveDialog.svelte | 30 +- 8 files changed, 505 insertions(+), 143 deletions(-) diff --git a/frontend/src/routes/(app)/members/+page.server.ts b/frontend/src/routes/(app)/members/+page.server.ts index 6e63458..7324498 100644 --- a/frontend/src/routes/(app)/members/+page.server.ts +++ b/frontend/src/routes/(app)/members/+page.server.ts @@ -12,6 +12,7 @@ export const load: PageServerLoad = async ({ fetch, locals }) => { return { members: membersRes.data ?? [], currentUserId: locals.benutzer!.id, - activeInvite: inviteRes.data?.data ?? null + activeInvite: inviteRes.data?.data ?? null, + householdName: locals.haushalt?.name ?? '' }; }; diff --git a/frontend/src/routes/(app)/members/+page.svelte b/frontend/src/routes/(app)/members/+page.svelte index 0f1591e..5c2dd64 100644 --- a/frontend/src/routes/(app)/members/+page.svelte +++ b/frontend/src/routes/(app)/members/+page.svelte @@ -70,7 +70,8 @@ Mitglieder — Mealprep
-

Mitglieder

+

Mitglieder

+

{members.length} Mitglieder{data.householdName ? ` · ${data.householdName}` : ''}

- - Einladen +
+
+
Mitglied einladen
+ + diff --git a/frontend/src/routes/(app)/members/InvitePanel.svelte b/frontend/src/routes/(app)/members/InvitePanel.svelte index 0eb9075..e7bd100 100644 --- a/frontend/src/routes/(app)/members/InvitePanel.svelte +++ b/frontend/src/routes/(app)/members/InvitePanel.svelte @@ -23,28 +23,117 @@ const date = new Date(dateStr); return date.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }); } + + const isExpiringSoon = $derived( + new Date(invite.expiresAt).getTime() - Date.now() <= 24 * 60 * 60 * 1000 + ); -
-

- {invite.shareUrl || invite.inviteCode} -

+
+
Einladelink teilen
+
Wer diesen Link öffnet, kann dem Haushalt als Mitglied beitreten.
-
- - -
-

- Läuft ab: {formatExpiry(invite.expiresAt)} -

+
+ Läuft ab: {formatExpiry(invite.expiresAt)} +
+ +
+ + diff --git a/frontend/src/routes/(app)/members/InvitePanel.test.ts b/frontend/src/routes/(app)/members/InvitePanel.test.ts index 77ba4f3..5212215 100644 --- a/frontend/src/routes/(app)/members/InvitePanel.test.ts +++ b/frontend/src/routes/(app)/members/InvitePanel.test.ts @@ -31,4 +31,9 @@ describe('InvitePanel', () => { await userEvent.click(screen.getByTestId('regenerate-btn')); expect(onregenerate).toHaveBeenCalledOnce(); }); + + it('shows the panel title', () => { + render(InvitePanel, { props: { invite, onregenerate: vi.fn() } }); + expect(screen.getByText('Einladelink teilen')).toBeInTheDocument(); + }); }); diff --git a/frontend/src/routes/(app)/members/MemberCard.svelte b/frontend/src/routes/(app)/members/MemberCard.svelte index cabcd40..7e2cfa3 100644 --- a/frontend/src/routes/(app)/members/MemberCard.svelte +++ b/frontend/src/routes/(app)/members/MemberCard.svelte @@ -1,6 +1,5 @@