Complete rebuild of 22-year-old PHP CMS as modern SaaS: Database (15 migrations, 42+ tables): - Foundation: account_settings, audit_log, GDPR register, cms_files - Module Engine: modules, fields, records, permissions, relations + RPC - Members: 45+ field member profiles, departments, roles, honors, SEPA mandates - Courses: courses, sessions, categories, instructors, locations, attendance - Bookings: rooms, guests, bookings with availability - Events: events, registrations, holiday passes - Finance: SEPA batches/items (pain.008/001 XML), invoices - Newsletter: campaigns, templates, recipients, subscriptions - Site Builder: site_pages (Puck JSON), site_settings, cms_posts - Portal Auth: member_portal_invitations, user linking Feature Packages (9): - @kit/module-builder — dynamic low-code CRUD engine - @kit/member-management — 31 API methods, 21 actions, 8 components - @kit/course-management, @kit/booking-management, @kit/event-management - @kit/finance — SEPA XML generator + IBAN validator - @kit/newsletter — campaigns + dispatch - @kit/document-generator — PDF/Excel/Word - @kit/site-builder — Puck visual editor, 15 blocks, public rendering Pages (60+): - Dashboard with real stats from all APIs - Full CRUD for all 8 domains with react-hook-form + Zod - Recharts statistics - German i18n throughout - Member portal with auth + invitation system - Public club websites via Puck at /club/[slug] Infrastructure: - Dockerfile (multi-stage, standalone output) - docker-compose.yml (Supabase self-hosted + Next.js) - Kong API gateway config - .env.production.example
82 lines
3.3 KiB
TypeScript
82 lines
3.3 KiB
TypeScript
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
|
import { createMemberManagementApi } from '@kit/member-management/api';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
|
|
import { Button } from '@kit/ui/button';
|
|
import { Badge } from '@kit/ui/badge';
|
|
import { CreditCard, Download } from 'lucide-react';
|
|
import { CmsPageShell } from '~/components/cms-page-shell';
|
|
import { EmptyState } from '~/components/empty-state';
|
|
|
|
interface Props {
|
|
params: Promise<{ account: string }>;
|
|
}
|
|
|
|
export default async function MemberCardsPage({ params }: Props) {
|
|
const { account } = await params;
|
|
const client = getSupabaseServerClient();
|
|
const { data: acct } = await client.from('accounts').select('id').eq('slug', account).single();
|
|
if (!acct) return <div>Konto nicht gefunden</div>;
|
|
|
|
const api = createMemberManagementApi(client);
|
|
const result = await api.listMembers(acct.id, { status: 'active', pageSize: 100 });
|
|
const members = result.data;
|
|
|
|
return (
|
|
<CmsPageShell account={account} title="Mitgliedsausweise" description="Ausweise erstellen und verwalten">
|
|
<div className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<p className="text-sm text-muted-foreground">{members.length} aktive Mitglieder</p>
|
|
<Button disabled>
|
|
<Download className="mr-2 h-4 w-4" />
|
|
Alle Ausweise generieren (PDF)
|
|
</Button>
|
|
</div>
|
|
|
|
{members.length === 0 ? (
|
|
<EmptyState
|
|
icon={<CreditCard className="h-8 w-8" />}
|
|
title="Keine aktiven Mitglieder"
|
|
description="Erstellen Sie zuerst Mitglieder, um Ausweise zu generieren."
|
|
actionLabel="Mitglieder verwalten"
|
|
actionHref={`/home/${account}/members-cms`}
|
|
/>
|
|
) : (
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
{members.map((m: Record<string, unknown>) => (
|
|
<Card key={String(m.id)}>
|
|
<CardContent className="p-4">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className="font-semibold">{String(m.last_name)}, {String(m.first_name)}</p>
|
|
<p className="text-xs text-muted-foreground">Nr. {String(m.member_number ?? '—')}</p>
|
|
</div>
|
|
<Badge variant="default">Aktiv</Badge>
|
|
</div>
|
|
<div className="mt-3 flex gap-2">
|
|
<Button size="sm" variant="outline" disabled>
|
|
<CreditCard className="mr-1 h-3 w-3" />
|
|
Ausweis
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>PDF-Generierung</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<p className="text-sm text-muted-foreground">
|
|
Die PDF-Generierung erfordert die Installation von <code>@react-pdf/renderer</code>.
|
|
Nach der Installation können Mitgliedsausweise einzeln oder als Stapel erstellt werden.
|
|
</p>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</CmsPageShell>
|
|
);
|
|
}
|