feat(invites): group picker in new-invite form

- load() fetches /api/groups in parallel with /api/invites; returns
  sorted groups array and groupsLoadError for partial failures
- create action forwards groupIds[] to POST /api/invites so invited
  users are placed in the selected groups on registration
- +page.svelte: group checkboxes via UserGroupsSection inside the form;
  amber warning banner when groups could not be loaded
- page.svelte.test.ts: groups checkboxes + warning banner tests
- page.server.test.ts: parallel fetch, sorting, error fallback,
  groupIds in POST body

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-14 15:20:53 +02:00
committed by marcel
parent 75453bed51
commit 510fa5e398
4 changed files with 324 additions and 12 deletions

View File

@@ -2,7 +2,8 @@
import { enhance } from '$app/forms';
import { m } from '$lib/paraglide/messages.js';
import { getErrorMessage } from '$lib/shared/errors';
import type { InviteListItem } from './+page.server.ts';
import UserGroupsSection from '$lib/user/UserGroupsSection.svelte';
import type { InviteListItem, UserGroup } from './+page.server.ts';
let {
data,
@@ -12,6 +13,8 @@ let {
invites: InviteListItem[];
status: string;
loadError: string | null;
groups: UserGroup[];
groupsLoadError: string | null;
};
form?: {
createError?: string;
@@ -253,6 +256,20 @@ function statusIcon(status: string) {
class="block w-full border border-line px-3 py-2 font-serif text-sm text-ink focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
/>
</div>
<div class="sm:col-span-2">
<p class="mb-2 font-sans text-xs font-bold tracking-widest text-ink-3 uppercase">
{m.admin_new_invite_groups()}
</p>
{#if data.groupsLoadError}
<div
class="rounded-sm border border-amber-200 bg-amber-50 px-3 py-2 font-sans text-xs text-amber-700"
>
{m.admin_invite_groups_load_error()}
</div>
{:else}
<UserGroupsSection groups={data.groups} />
{/if}
</div>
{#if form?.createError}
<div class="font-sans text-xs font-medium text-red-600 sm:col-span-2">
{getErrorMessage(form.createError)}