feat: unify tenant admin ui and add photo moderation
This commit is contained in:
@@ -5,7 +5,6 @@ import { useTranslation } from 'react-i18next';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
|
||||
import { AdminLayout } from '../components/AdminLayout';
|
||||
@@ -13,10 +12,11 @@ import { getTenantPackagesOverview, getTenantPaddleTransactions, PaddleTransacti
|
||||
import { isAuthError } from '../auth/tokens';
|
||||
import {
|
||||
TenantHeroCard,
|
||||
FrostedCard,
|
||||
FrostedSurface,
|
||||
tenantHeroPrimaryButtonClass,
|
||||
tenantHeroSecondaryButtonClass,
|
||||
SectionCard,
|
||||
SectionHeader,
|
||||
} from '../components/tenant';
|
||||
|
||||
type PackageWarning = { id: string; tone: 'warning' | 'danger'; message: string };
|
||||
@@ -196,25 +196,20 @@ export default function BillingPage() {
|
||||
<BillingSkeleton />
|
||||
) : (
|
||||
<>
|
||||
<FrostedCard className="mt-6 border border-white/20">
|
||||
<CardHeader className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||
<div>
|
||||
<CardTitle className="flex items-center gap-2 text-xl text-slate-900">
|
||||
<Sparkles className="h-5 w-5 text-pink-500" />
|
||||
{t('billing.sections.overview.title')}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-sm text-slate-600">
|
||||
{t('billing.sections.overview.description')}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Badge className={activePackage ? 'bg-pink-500/10 text-pink-700 dark:bg-pink-500/20 dark:text-pink-200' : 'bg-slate-200 text-slate-700 dark:bg-slate-800 dark:text-slate-200'}>
|
||||
{activePackage ? activePackage.package_name : t('billing.sections.overview.emptyBadge')}
|
||||
</Badge>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{activePackage ? (
|
||||
<div className="space-y-4">
|
||||
{activeWarnings.length > 0 && (
|
||||
<SectionCard className="mt-6 space-y-5">
|
||||
<SectionHeader
|
||||
eyebrow={t('billing.sections.overview.badge', 'Aktuelles Paket')}
|
||||
title={t('billing.sections.overview.title')}
|
||||
description={t('billing.sections.overview.description')}
|
||||
endSlot={(
|
||||
<Badge className={activePackage ? 'bg-pink-500/10 text-pink-700 dark:bg-pink-500/20 dark:text-pink-200' : 'bg-slate-200 text-slate-700 dark:bg-slate-800 dark:text-slate-200'}>
|
||||
{activePackage ? activePackage.package_name : t('billing.sections.overview.emptyBadge')}
|
||||
</Badge>
|
||||
)}
|
||||
/>
|
||||
{activePackage ? (
|
||||
<div className="space-y-4">
|
||||
{activeWarnings.length > 0 && (
|
||||
<div className="space-y-2">
|
||||
{activeWarnings.map((warning) => (
|
||||
<Alert
|
||||
@@ -263,20 +258,15 @@ export default function BillingPage() {
|
||||
) : (
|
||||
<EmptyState message={t('billing.sections.overview.empty')} />
|
||||
)}
|
||||
</CardContent>
|
||||
</FrostedCard>
|
||||
</SectionCard>
|
||||
|
||||
<FrostedCard className="border border-white/20">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-xl text-slate-900">
|
||||
<Sparkles className="h-5 w-5 text-amber-500" />
|
||||
{t('billing.sections.packages.title')}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-sm text-slate-600">
|
||||
{t('billing.sections.packages.description')}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<SectionCard className="space-y-4">
|
||||
<SectionHeader
|
||||
eyebrow={t('billing.sections.packages.badge', 'Pakete')}
|
||||
title={t('billing.sections.packages.title')}
|
||||
description={t('billing.sections.packages.description')}
|
||||
/>
|
||||
<div className="space-y-3">
|
||||
{packages.length === 0 ? (
|
||||
<EmptyState message={t('billing.sections.packages.empty')} />
|
||||
) : (
|
||||
@@ -295,20 +285,16 @@ export default function BillingPage() {
|
||||
);
|
||||
})
|
||||
)}
|
||||
</CardContent>
|
||||
</FrostedCard>
|
||||
</div>
|
||||
</SectionCard>
|
||||
|
||||
<FrostedCard className="border border-white/20">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-xl text-slate-900">
|
||||
<Sparkles className="h-5 w-5 text-sky-500" />
|
||||
{t('billing.sections.transactions.title')}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-sm text-slate-600">
|
||||
{t('billing.sections.transactions.description')}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<SectionCard className="space-y-4">
|
||||
<SectionHeader
|
||||
eyebrow={t('billing.sections.transactions.badge', 'Transaktionen')}
|
||||
title={t('billing.sections.transactions.title')}
|
||||
description={t('billing.sections.transactions.description')}
|
||||
/>
|
||||
<div className="space-y-3">
|
||||
{transactions.length === 0 ? (
|
||||
<EmptyState message={t('billing.sections.transactions.empty')} />
|
||||
) : (
|
||||
@@ -341,8 +327,8 @@ export default function BillingPage() {
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</CardContent>
|
||||
</FrostedCard>
|
||||
</div>
|
||||
</SectionCard>
|
||||
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user