neues Admin UI Layout eingeführt. Alle Tests auf den neusten Stand gebracht.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user