'use client'; import { useState, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { Mail, XCircle, Send } from 'lucide-react'; import { useTranslations } from 'next-intl'; import { inviteMemberToPortal, revokePortalInvitation, } from '@kit/member-management/actions/member-actions'; import { formatDate } from '@kit/shared/dates'; import { Badge } from '@kit/ui/badge'; import { Button } from '@kit/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card'; import { useActionWithToast } from '@kit/ui/use-action-with-toast'; interface Invitation { id: string; member_id: string; email: string; status: string; created_at: string; expires_at: string; accepted_at: string | null; } interface MemberOption { id: string; first_name: string; last_name: string; email: string | null; } interface InvitationsViewProps { invitations: Invitation[]; members: MemberOption[]; accountId: string; account: string; } const STATUS_LABELS: Record = { pending: 'Ausstehend', accepted: 'Angenommen', revoked: 'Widerrufen', expired: 'Abgelaufen', }; const STATUS_COLORS: Record< string, 'default' | 'secondary' | 'destructive' | 'outline' > = { pending: 'default', accepted: 'secondary', revoked: 'destructive', expired: 'outline', }; export function InvitationsView({ invitations, members, accountId, }: InvitationsViewProps) { const t = useTranslations('members'); const router = useRouter(); const [showDialog, setShowDialog] = useState(false); const [selectedMemberId, setSelectedMemberId] = useState(''); const [email, setEmail] = useState(''); const { execute: executeInvite, isPending: isInviting } = useActionWithToast( inviteMemberToPortal, { successMessage: 'Einladung gesendet', onSuccess: () => { setShowDialog(false); setSelectedMemberId(''); setEmail(''); router.refresh(); }, }, ); const { execute: executeRevoke, isPending: isRevoking } = useActionWithToast( revokePortalInvitation, { successMessage: 'Einladung widerrufen', onSuccess: () => router.refresh(), }, ); const handleInvite = useCallback(() => { if (!selectedMemberId || !email) return; executeInvite({ memberId: selectedMemberId, accountId, email, }); }, [executeInvite, selectedMemberId, accountId, email]); const handleRevoke = useCallback( (invitationId: string) => { if (!window.confirm('Einladung wirklich widerrufen?')) return; executeRevoke({ invitationId }); }, [executeRevoke], ); // When a member is selected, pre-fill email const handleMemberChange = useCallback( (memberId: string) => { setSelectedMemberId(memberId); const member = members.find((m) => m.id === memberId); if (member?.email) { setEmail(member.email); } }, [members], ); return (
{/* Actions */}
{/* Send Invitation Dialog */} {showDialog && ( Einladung senden
setEmail(e.target.value)} placeholder={t('invitations.emailPlaceholder')} data-test="invite-email-input" className="border-input bg-background flex h-9 w-full rounded-md border px-3 py-1 text-sm" />
)} {/* Invitations Table */} Einladungen ({invitations.length}) {invitations.length === 0 ? (

Keine Einladungen vorhanden

{t('invitations.emptyDescription')}

) : (
{invitations.map((inv) => ( ))}
E-Mail Status Erstellt Läuft ab Aktionen
{inv.email} {STATUS_LABELS[inv.status] ?? inv.status} {formatDate(inv.created_at)} {formatDate(inv.expires_at)} {inv.status === 'pending' && ( )}
)}
); }