Fix auth translations and admin PWA UI
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-01-16 12:14:53 +01:00
parent 292c8f0b26
commit 918bff08aa
44 changed files with 2504 additions and 677 deletions

View File

@@ -8,6 +8,7 @@ import { Pressable } from '@tamagui/react-native-web-lite';
import { Slider } from 'tamagui';
import { MobileShell, HeaderActionButton } from './components/MobileShell';
import { MobileCard, CTAButton, SkeletonCard } from './components/Primitives';
import { MobileColorInput, MobileField, MobileFileInput, MobileInput, MobileSelect } from './components/FormControls';
import { TenantEvent, getEvent, updateEvent, getTenantFonts, getTenantSettings, TenantFont, WatermarkSettings, trackOnboarding } from '../api';
import { isAuthError } from '../auth/tokens';
import { ApiError, getApiErrorMessage } from '../lib/apiError';
@@ -363,22 +364,17 @@ export default function MobileBrandingPage() {
{t('events.watermark.title', 'Wasserzeichen')}
</Text>
<InputField
label={t('events.watermark.mode', 'Modus')}
value={mode}
onChange={(value) => {
if (controlsLocked) return;
if (value === 'custom' || value === 'base' || value === 'off') {
setWatermarkForm((prev) => ({ ...prev, mode: value as WatermarkForm['mode'] }));
}
}}
onPicker={() => undefined}
>
<select
<MobileField label={t('events.watermark.mode', 'Modus')}>
<MobileSelect
value={mode}
disabled={controlsLocked}
onChange={(event) => setWatermarkForm((prev) => ({ ...prev, mode: event.target.value as WatermarkForm['mode'] }))}
style={{ width: '100%', height: 40, border: 'none', outline: 'none', background: 'transparent' }}
onChange={(event) => {
const value = event.target.value;
if (controlsLocked) return;
if (value === 'custom' || value === 'base' || value === 'off') {
setWatermarkForm((prev) => ({ ...prev, mode: value as WatermarkForm['mode'] }));
}
}}
>
<option value="base">{t('events.watermark.modeBase', 'Basis')}</option>
<option value="custom" disabled={watermarkLocked}>
@@ -387,8 +383,8 @@ export default function MobileBrandingPage() {
<option value="off" disabled={policyLabel === 'basic'}>
{t('events.watermark.modeOff', 'Deaktiviert')}
</option>
</select>
</InputField>
</MobileSelect>
</MobileField>
{mode === 'custom' && !controlsLocked ? (
<YStack space="$2">
@@ -414,11 +410,9 @@ export default function MobileBrandingPage() {
</Text>
</XStack>
</Pressable>
<input
<MobileFileInput
id="watermark-upload-input"
type="file"
accept="image/png,image/jpeg,image/webp,image/svg+xml"
style={{ display: 'none' }}
onChange={(event) => {
const file = event.target.files?.[0];
if (!file) return;
@@ -855,11 +849,9 @@ export default function MobileBrandingPage() {
</Pressable>
</>
)}
<input
<MobileFileInput
id="branding-logo-input"
type="file"
accept="image/*"
style={{ display: 'none' }}
disabled={brandingDisabled}
onChange={(event) => {
const file = event.target.files?.[0];
@@ -1171,24 +1163,22 @@ function ColorField({
onChange: (next: string) => void;
disabled?: boolean;
}) {
const { textStrong, muted, border, surface } = useAdminTheme();
const { textStrong, muted } = useAdminTheme();
return (
<YStack space="$2" opacity={disabled ? 0.6 : 1}>
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
{label}
</Text>
<XStack alignItems="center" space="$2">
<input
type="color"
value={value}
onChange={(event) => onChange(event.target.value)}
disabled={disabled}
style={{ width: 52, height: 52, borderRadius: 12, border: `1px solid ${border}`, background: surface }}
/>
<Text fontSize="$sm" color={muted}>
{value}
</Text>
</XStack>
<XStack alignItems="center" space="$2">
<MobileColorInput
value={value}
onChange={(event) => onChange(event.target.value)}
disabled={disabled}
/>
<Text fontSize="$sm" color={muted}>
{value}
</Text>
</XStack>
</YStack>
);
}
@@ -1211,7 +1201,6 @@ function InputField({
placeholder,
onChange,
onPicker,
children,
disabled,
}: {
label: string;
@@ -1219,51 +1208,27 @@ function InputField({
placeholder?: string;
onChange: (next: string) => void;
onPicker?: () => void;
children?: React.ReactNode;
disabled?: boolean;
}) {
const { textStrong, border, surface, primary } = useAdminTheme();
const { primary } = useAdminTheme();
return (
<YStack space="$2" opacity={disabled ? 0.6 : 1}>
<Text fontSize="$sm" fontWeight="700" color={textStrong}>
{label}
</Text>
<XStack
alignItems="center"
borderRadius={12}
borderWidth={1}
borderColor={border}
paddingLeft="$3"
paddingRight="$2"
height={48}
backgroundColor={surface}
space="$2"
>
{children ?? (
<input
type="text"
value={value}
placeholder={placeholder}
onChange={(event) => onChange(event.target.value)}
disabled={disabled}
style={{
flex: 1,
height: '100%',
border: 'none',
outline: 'none',
fontSize: 14,
background: 'transparent',
}}
onFocus={onPicker}
/>
)}
<MobileField label={label}>
<XStack alignItems="center" space="$2">
<MobileInput
value={value}
placeholder={placeholder}
onChange={(event) => onChange(event.target.value)}
onFocus={onPicker}
disabled={disabled}
style={{ flex: 1 }}
/>
{onPicker ? (
<Pressable onPress={onPicker} disabled={disabled}>
<ChevronDown size={16} color={primary} />
</Pressable>
) : null}
</XStack>
</YStack>
</MobileField>
);
}