Add account hierarchy framework with migrations, RLS policies, and UI components

This commit is contained in:
T. Zehetbauer
2026-03-31 22:18:04 +02:00
parent 7e7da0b465
commit 59546ad6d2
262 changed files with 11671 additions and 3927 deletions

View File

@@ -1,9 +1,12 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { createFischereiApi } from '@kit/fischerei/api';
import { FischereiTabNavigation, CatchBooksDataTable } from '@kit/fischerei/components';
import {
FischereiTabNavigation,
CatchBooksDataTable,
} from '@kit/fischerei/components';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { CmsPageShell } from '~/components/cms-page-shell';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;

View File

@@ -1,16 +1,22 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { createFischereiApi } from '@kit/fischerei/api';
import { FischereiTabNavigation, CompetitionsDataTable } from '@kit/fischerei/components';
import {
FischereiTabNavigation,
CompetitionsDataTable,
} from '@kit/fischerei/components';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { CmsPageShell } from '~/components/cms-page-shell';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;
searchParams: Promise<Record<string, string | string[] | undefined>>;
}
export default async function CompetitionsPage({ params, searchParams }: Props) {
export default async function CompetitionsPage({
params,
searchParams,
}: Props) {
const { account } = await params;
const search = await searchParams;
const client = getSupabaseServerClient();

View File

@@ -1,13 +1,13 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { createFischereiApi } from '@kit/fischerei/api';
import { FischereiTabNavigation } from '@kit/fischerei/components';
import { CmsPageShell } from '~/components/cms-page-shell';
import { LEASE_PAYMENT_LABELS } from '@kit/fischerei/lib/fischerei-constants';
import { formatDate } from '@kit/shared/dates';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { Badge } from '@kit/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
import { LEASE_PAYMENT_LABELS } from '@kit/fischerei/lib/fischerei-constants';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;
@@ -54,7 +54,7 @@ export default async function LeasesPage({ params, searchParams }: Props) {
<h3 className="text-lg font-semibold">
Keine Pachten vorhanden
</h3>
<p className="mt-1 max-w-sm text-sm text-muted-foreground">
<p className="text-muted-foreground mt-1 max-w-sm text-sm">
Erstellen Sie Ihren ersten Pachtvertrag.
</p>
</div>
@@ -62,22 +62,32 @@ export default async function LeasesPage({ params, searchParams }: Props) {
<div className="rounded-md border">
<table className="w-full text-sm">
<thead>
<tr className="border-b bg-muted/50">
<tr className="bg-muted/50 border-b">
<th className="p-3 text-left font-medium">Verpächter</th>
<th className="p-3 text-left font-medium">Gewässer</th>
<th className="p-3 text-left font-medium">Beginn</th>
<th className="p-3 text-left font-medium">Ende</th>
<th className="p-3 text-right font-medium">Jahresbetrag ()</th>
<th className="p-3 text-right font-medium">
Jahresbetrag ()
</th>
<th className="p-3 text-left font-medium">Zahlungsart</th>
</tr>
</thead>
<tbody>
{result.data.map((lease: Record<string, unknown>) => {
const waters = lease.waters as Record<string, unknown> | null;
const paymentMethod = String(lease.payment_method ?? 'ueberweisung');
const waters = lease.waters as Record<
string,
unknown
> | null;
const paymentMethod = String(
lease.payment_method ?? 'ueberweisung',
);
return (
<tr key={String(lease.id)} className="border-b hover:bg-muted/30">
<tr
key={String(lease.id)}
className="hover:bg-muted/30 border-b"
>
<td className="p-3 font-medium">
{String(lease.lessor_name)}
</td>
@@ -85,13 +95,11 @@ export default async function LeasesPage({ params, searchParams }: Props) {
{waters ? String(waters.name) : '—'}
</td>
<td className="p-3">
{lease.start_date
? new Date(String(lease.start_date)).toLocaleDateString('de-DE')
: '—'}
{formatDate(lease.start_date)}
</td>
<td className="p-3">
{lease.end_date
? new Date(String(lease.end_date)).toLocaleDateString('de-DE')
? formatDate(lease.end_date)
: 'unbefristet'}
</td>
<td className="p-3 text-right">
@@ -101,7 +109,8 @@ export default async function LeasesPage({ params, searchParams }: Props) {
</td>
<td className="p-3">
<Badge variant="outline">
{LEASE_PAYMENT_LABELS[paymentMethod] ?? paymentMethod}
{LEASE_PAYMENT_LABELS[paymentMethod] ??
paymentMethod}
</Badge>
</td>
</tr>

View File

@@ -1,9 +1,12 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { createFischereiApi } from '@kit/fischerei/api';
import { FischereiTabNavigation, FischereiDashboard } from '@kit/fischerei/components';
import {
FischereiTabNavigation,
FischereiDashboard,
} from '@kit/fischerei/components';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { CmsPageShell } from '~/components/cms-page-shell';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface PageProps {
params: Promise<{ account: string }>;

View File

@@ -1,10 +1,10 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { createFischereiApi } from '@kit/fischerei/api';
import { FischereiTabNavigation } from '@kit/fischerei/components';
import { CmsPageShell } from '~/components/cms-page-shell';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;
@@ -45,7 +45,7 @@ export default async function PermitsPage({ params }: Props) {
<h3 className="text-lg font-semibold">
Keine Erlaubnisscheine vorhanden
</h3>
<p className="mt-1 max-w-sm text-sm text-muted-foreground">
<p className="text-muted-foreground mt-1 max-w-sm text-sm">
Erstellen Sie Ihren ersten Erlaubnisschein.
</p>
</div>
@@ -53,22 +53,36 @@ export default async function PermitsPage({ params }: Props) {
<div className="rounded-md border">
<table className="w-full text-sm">
<thead>
<tr className="border-b bg-muted/50">
<tr className="bg-muted/50 border-b">
<th className="p-3 text-left font-medium">Bezeichnung</th>
<th className="p-3 text-left font-medium">Kurzcode</th>
<th className="p-3 text-left font-medium">Hauptgewässer</th>
<th className="p-3 text-right font-medium">Gesamtmenge</th>
<th className="p-3 text-center font-medium">Zum Verkauf</th>
<th className="p-3 text-left font-medium">
Hauptgewässer
</th>
<th className="p-3 text-right font-medium">
Gesamtmenge
</th>
<th className="p-3 text-center font-medium">
Zum Verkauf
</th>
</tr>
</thead>
<tbody>
{permits.map((permit: Record<string, unknown>) => {
const waters = permit.waters as Record<string, unknown> | null;
const waters = permit.waters as Record<
string,
unknown
> | null;
return (
<tr key={String(permit.id)} className="border-b hover:bg-muted/30">
<td className="p-3 font-medium">{String(permit.name)}</td>
<td className="p-3 text-muted-foreground">
<tr
key={String(permit.id)}
className="hover:bg-muted/30 border-b"
>
<td className="p-3 font-medium">
{String(permit.name)}
</td>
<td className="text-muted-foreground p-3">
{String(permit.short_code ?? '—')}
</td>
<td className="p-3">

View File

@@ -1,8 +1,11 @@
import {
FischereiTabNavigation,
CreateSpeciesForm,
} from '@kit/fischerei/components';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { FischereiTabNavigation, CreateSpeciesForm } from '@kit/fischerei/components';
import { CmsPageShell } from '~/components/cms-page-shell';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;

View File

@@ -1,9 +1,12 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { createFischereiApi } from '@kit/fischerei/api';
import { FischereiTabNavigation, SpeciesDataTable } from '@kit/fischerei/components';
import {
FischereiTabNavigation,
SpeciesDataTable,
} from '@kit/fischerei/components';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { CmsPageShell } from '~/components/cms-page-shell';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;

View File

@@ -1,9 +1,9 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { FischereiTabNavigation } from '@kit/fischerei/components';
import { CmsPageShell } from '~/components/cms-page-shell';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { Card, CardContent, CardHeader, CardTitle } from '@kit/ui/card';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;
@@ -37,9 +37,12 @@ export default async function StatisticsPage({ params }: Props) {
</CardHeader>
<CardContent>
<div className="flex flex-col items-center justify-center rounded-lg border border-dashed p-12 text-center">
<h3 className="text-lg font-semibold">Noch keine Daten vorhanden</h3>
<p className="mt-1 max-w-sm text-sm text-muted-foreground">
Sobald Fangbücher eingereicht und geprüft werden, erscheinen hier Statistiken und Auswertungen.
<h3 className="text-lg font-semibold">
Noch keine Daten vorhanden
</h3>
<p className="text-muted-foreground mt-1 max-w-sm text-sm">
Sobald Fangbücher eingereicht und geprüft werden, erscheinen
hier Statistiken und Auswertungen.
</p>
</div>
</CardContent>

View File

@@ -1,9 +1,12 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { createFischereiApi } from '@kit/fischerei/api';
import { FischereiTabNavigation, CreateStockingForm } from '@kit/fischerei/components';
import {
FischereiTabNavigation,
CreateStockingForm,
} from '@kit/fischerei/components';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { CmsPageShell } from '~/components/cms-page-shell';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;

View File

@@ -1,9 +1,12 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { createFischereiApi } from '@kit/fischerei/api';
import { FischereiTabNavigation, StockingDataTable } from '@kit/fischerei/components';
import {
FischereiTabNavigation,
StockingDataTable,
} from '@kit/fischerei/components';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { CmsPageShell } from '~/components/cms-page-shell';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;

View File

@@ -1,8 +1,11 @@
import {
FischereiTabNavigation,
CreateWaterForm,
} from '@kit/fischerei/components';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { FischereiTabNavigation, CreateWaterForm } from '@kit/fischerei/components';
import { CmsPageShell } from '~/components/cms-page-shell';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;

View File

@@ -1,9 +1,12 @@
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { createFischereiApi } from '@kit/fischerei/api';
import { FischereiTabNavigation, WatersDataTable } from '@kit/fischerei/components';
import {
FischereiTabNavigation,
WatersDataTable,
} from '@kit/fischerei/components';
import { getSupabaseServerClient } from '@kit/supabase/server-client';
import { CmsPageShell } from '~/components/cms-page-shell';
import { AccountNotFound } from '~/components/account-not-found';
import { CmsPageShell } from '~/components/cms-page-shell';
interface Props {
params: Promise<{ account: string }>;