further improvements for the mobile admin

This commit is contained in:
Codex Agent
2025-12-12 21:47:34 +01:00
parent 1719d96fed
commit a35f81705d
15 changed files with 914 additions and 290 deletions

View File

@@ -5,6 +5,7 @@ import { Shield, Bell, LogOut, User } from 'lucide-react';
import { YStack, XStack } from '@tamagui/stacks';
import { SizableText as Text } from '@tamagui/text';
import { Pressable } from '@tamagui/react-native-web-lite';
import { Switch } from '@tamagui/switch';
import { MobileShell } from './components/MobileShell';
import { MobileCard, CTAButton, PillBadge } from './components/Primitives';
import { useAuth } from '../auth/context';
@@ -18,6 +19,19 @@ import { adminPath } from '../constants';
type PreferenceKey = keyof NotificationPreferences;
const AVAILABLE_PREFS: PreferenceKey[] = [
'photo_thresholds',
'photo_limits',
'guest_thresholds',
'guest_limits',
'gallery_warnings',
'gallery_expired',
'event_thresholds',
'event_limits',
'package_expiring',
'package_expired',
];
export default function MobileSettingsPage() {
const { t } = useTranslation('management');
const navigate = useNavigate();
@@ -33,8 +47,15 @@ export default function MobileSettingsPage() {
setLoading(true);
try {
const result = await getNotificationPreferences();
setPreferences(result.preferences);
setDefaults(result.defaults ?? {});
const defaultsMerged: NotificationPreferences = result.defaults ?? {};
const prefs = { ...defaultsMerged, ...(result.preferences ?? {}) };
AVAILABLE_PREFS.forEach((key) => {
if (prefs[key] === undefined) {
prefs[key] = defaultsMerged[key] ?? false;
}
});
setPreferences(prefs);
setDefaults(defaultsMerged);
setError(null);
} catch (err) {
setError(getApiErrorMessage(err, t('settings.notifications.errorLoad', 'Benachrichtigungen konnten nicht geladen werden.')));
@@ -54,7 +75,11 @@ export default function MobileSettingsPage() {
const handleSave = async () => {
setSaving(true);
try {
await updateNotificationPreferences(preferences);
const payload: NotificationPreferences = {};
AVAILABLE_PREFS.forEach((key) => {
payload[key] = Boolean(preferences[key]);
});
await updateNotificationPreferences(payload);
setError(null);
} catch (err) {
setError(getApiErrorMessage(err, t('settings.notifications.errorSave', 'Speichern fehlgeschlagen')));
@@ -109,21 +134,35 @@ export default function MobileSettingsPage() {
</Text>
) : (
<YStack space="$2">
{(['task_updates','photo_limits','photo_thresholds','guest_limits','guest_thresholds','purchase_limits','billing','alerts'] as PreferenceKey[]).map((key) => {
const prefKey = key as PreferenceKey;
return (
<XStack key={prefKey} alignItems="center" justifyContent="space-between" borderBottomWidth={1} borderColor="#e5e7eb" paddingBottom="$2" paddingTop="$1.5">
<Text fontSize="$sm" color="#0f172a">
{t(`mobileSettings.pref.${prefKey}`, prefKey)}
{AVAILABLE_PREFS.map((key) => (
<XStack
key={key}
alignItems="center"
justifyContent="space-between"
borderBottomWidth={1}
borderColor="#e5e7eb"
paddingBottom="$2"
paddingTop="$1.5"
space="$2"
>
<YStack flex={1} minWidth={0} space="$1">
<Text fontSize="$sm" color="#0f172a" fontWeight="700">
{t(`settings.notifications.keys.${key}.label`, key)}
</Text>
<input
type="checkbox"
checked={Boolean(preferences[prefKey])}
onChange={() => togglePref(prefKey)}
/>
</XStack>
);
})}
<Text fontSize="$xs" color="#6b7280">
{t(`settings.notifications.keys.${key}.description`, '')}
</Text>
</YStack>
<Switch
size="$4"
checked={Boolean(preferences[key])}
onCheckedChange={() => togglePref(key)}
aria-label={t(`settings.notifications.keys.${key}.label`, key)}
>
<Switch.Thumb />
</Switch>
</XStack>
))}
</YStack>
)}
<XStack space="$2">