neues Admin UI Layout eingeführt. Alle Tests auf den neusten Stand gebracht.

This commit is contained in:
Codex Agent
2025-12-30 10:24:06 +01:00
parent 902e78cae9
commit efe2f25b3e
85 changed files with 95235 additions and 19197 deletions

View File

@@ -28,12 +28,14 @@ import { adminPath } from '../constants';
import { selectAddonKeyForScope } from './addons';
import { LegalConsentSheet } from './components/LegalConsentSheet';
import { useBackNavigation } from './hooks/useBackNavigation';
import { useAdminTheme } from './theme';
export default function MobileEventRecapPage() {
const { slug } = useParams<{ slug?: string }>();
const navigate = useNavigate();
const location = useLocation();
const { t } = useTranslation('management');
const { textStrong, text, muted, subtle, danger, border, primary, accentSoft } = useAdminTheme();
const [event, setEvent] = React.useState<TenantEvent | null>(null);
const [stats, setStats] = React.useState<EventStats | null>(null);
@@ -92,7 +94,7 @@ export default function MobileEventRecapPage() {
return (
<MobileShell activeTab="home" title={t('events.errors.notFoundTitle', 'Event nicht gefunden')} onBack={back}>
<MobileCard>
<Text color="#b91c1c">{t('events.errors.notFoundBody', 'Kehre zur Eventliste zurück und wähle dort ein Event aus.')}</Text>
<Text color={danger}>{t('events.errors.notFoundBody', 'Kehre zur Eventliste zurück und wähle dort ein Event aus.')}</Text>
</MobileCard>
</MobileShell>
);
@@ -202,13 +204,13 @@ export default function MobileEventRecapPage() {
onBack={back}
headerActions={
<HeaderActionButton onPress={() => load()} ariaLabel={t('common.refresh', 'Refresh')}>
<RefreshCcw size={18} color="#0f172a" />
<RefreshCcw size={18} color={textStrong} />
</HeaderActionButton>
}
>
{error ? (
<MobileCard>
<Text color="#b91c1c">{error}</Text>
<Text color={danger}>{error}</Text>
</MobileCard>
) : null}
@@ -223,11 +225,11 @@ export default function MobileEventRecapPage() {
<MobileCard space="$2">
<XStack alignItems="center" justifyContent="space-between">
<YStack space="$1">
<Text fontSize="$xs" color="#6b7280" fontWeight="700" letterSpacing={1.2}>
<Text fontSize="$xs" color={muted} fontWeight="700" letterSpacing={1.2}>
{t('events.recap.badge', 'Nachbereitung')}
</Text>
<Text fontSize="$lg" fontWeight="800" color="#0f172a">{resolveName(event.name)}</Text>
<Text fontSize="$sm" color="#6b7280">
<Text fontSize="$lg" fontWeight="800" color={textStrong}>{resolveName(event.name)}</Text>
<Text fontSize="$sm" color={muted}>
{t('events.recap.subtitle', 'Abschluss, Export und Galerie-Laufzeit verwalten.')}
</Text>
</YStack>
@@ -248,7 +250,7 @@ export default function MobileEventRecapPage() {
<MobileCard space="$2">
<XStack alignItems="center" justifyContent="space-between">
<Text fontSize="$md" fontWeight="800" color="#0f172a">
<Text fontSize="$md" fontWeight="800" color={textStrong}>
{t('events.recap.galleryTitle', 'Galerie-Status')}
</Text>
<PillBadge tone="muted">{t('events.recap.galleryCounts', '{{photos}} Fotos, {{pending}} offen, {{likes}} Likes', galleryCounts)}</PillBadge>
@@ -262,17 +264,17 @@ export default function MobileEventRecapPage() {
<MobileCard space="$2">
<XStack alignItems="center" space="$2">
<Link2 size={16} color="#0f172a" />
<Text fontSize="$md" fontWeight="800" color="#0f172a">
<Link2 size={16} color={textStrong} />
<Text fontSize="$md" fontWeight="800" color={textStrong}>
{t('events.recap.shareLink', 'Gäste-Link')}
</Text>
</XStack>
{guestLink ? (
<Text fontSize="$sm" color="#111827" selectable>
<Text fontSize="$sm" color={text} selectable>
{guestLink}
</Text>
) : (
<Text fontSize="$sm" color="#6b7280">
<Text fontSize="$sm" color={muted}>
{t('events.recap.noPublicUrl', 'Kein Gäste-Link gesetzt. Lege den öffentlichen Link im Event-Setup fest.')}
</Text>
)}
@@ -284,7 +286,11 @@ export default function MobileEventRecapPage() {
</XStack>
{activeInvite?.qr_code_data_url ? (
<XStack space="$2" alignItems="center" marginTop="$2">
<img src={activeInvite.qr_code_data_url} alt="QR" style={{ width: 96, height: 96 }} />
<img
src={activeInvite.qr_code_data_url}
alt={t('events.qr.qrAlt', 'QR code')}
style={{ width: 96, height: 96 }}
/>
<CTAButton label={t('events.recap.downloadQr', 'QR herunterladen')} tone="ghost" onPress={() => downloadQr(activeInvite.qr_code_data_url)} />
</XStack>
) : null}
@@ -292,12 +298,12 @@ export default function MobileEventRecapPage() {
<MobileCard space="$2">
<XStack alignItems="center" space="$2">
<ShoppingCart size={16} color="#0f172a" />
<Text fontSize="$md" fontWeight="800" color="#0f172a">
<ShoppingCart size={16} color={textStrong} />
<Text fontSize="$md" fontWeight="800" color={textStrong}>
{t('events.sections.addons.title', 'Add-ons & Upgrades')}
</Text>
</XStack>
<Text fontSize="$sm" color="#6b7280">
<Text fontSize="$sm" color={muted}>
{t('events.sections.addons.description', 'Zusätzliche Kontingente freischalten.')}
</Text>
<CTAButton
@@ -311,8 +317,8 @@ export default function MobileEventRecapPage() {
<MobileCard space="$2">
<XStack alignItems="center" space="$2">
<Shield size={16} color="#0f172a" />
<Text fontSize="$md" fontWeight="800" color="#0f172a">
<Shield size={16} color={textStrong} />
<Text fontSize="$md" fontWeight="800" color={textStrong}>
{t('events.recap.settingsTitle', 'Gast-Einstellungen')}
</Text>
</XStack>
@@ -330,12 +336,12 @@ export default function MobileEventRecapPage() {
<MobileCard space="$2">
<XStack alignItems="center" space="$2">
<Archive size={16} color="#0f172a" />
<Text fontSize="$md" fontWeight="800" color="#0f172a">
<Archive size={16} color={textStrong} />
<Text fontSize="$md" fontWeight="800" color={textStrong}>
{t('events.recap.archiveTitle', 'Event archivieren')}
</Text>
</XStack>
<Text fontSize="$sm" color="#6b7280">
<Text fontSize="$sm" color={muted}>
{t('events.recap.archiveCopy', 'Schließt die Galerie und markiert das Event als abgeschlossen.')}
</Text>
<CTAButton label={t('events.recap.archive', 'Archivieren')} onPress={() => archiveEvent()} loading={archiveBusy} />
@@ -343,8 +349,8 @@ export default function MobileEventRecapPage() {
<MobileCard space="$2">
<XStack alignItems="center" space="$2">
<Sparkles size={16} color="#0f172a" />
<Text fontSize="$md" fontWeight="800" color="#0f172a">
<Sparkles size={16} color={textStrong} />
<Text fontSize="$md" fontWeight="800" color={textStrong}>
{t('events.recap.feedbackTitle', 'Wie lief das Event?')}
</Text>
</XStack>
@@ -372,12 +378,13 @@ export default function MobileEventRecapPage() {
}
function Stat({ label, value }: { label: string; value: string }) {
const { border, muted, textStrong } = useAdminTheme();
return (
<MobileCard borderColor="#e5e7eb" space="$1.5">
<Text fontSize="$xs" color="#6b7280">
<MobileCard borderColor={border} space="$1.5">
<Text fontSize="$xs" color={muted}>
{label}
</Text>
<Text fontSize="$md" fontWeight="800" color="#0f172a">
<Text fontSize="$md" fontWeight="800" color={textStrong}>
{value}
</Text>
</MobileCard>
@@ -385,9 +392,10 @@ function Stat({ label, value }: { label: string; value: string }) {
}
function ToggleRow({ label, value, onToggle }: { label: string; value: boolean; onToggle: (value: boolean) => void }) {
const { textStrong } = useAdminTheme();
return (
<XStack alignItems="center" justifyContent="space-between" marginTop="$1.5">
<Text fontSize="$sm" color="#0f172a">
<Text fontSize="$sm" color={textStrong}>
{label}
</Text>
<input