Fix PayPal billing flow and mobile admin UX
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-02-05 10:19:29 +01:00
parent c43327af74
commit 0d7a861875
39 changed files with 1630 additions and 253 deletions

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { ChevronRight, CreditCard, FileText, HelpCircle, Moon, Sun, User, X } from 'lucide-react';
import { ChevronRight, CreditCard, FileText, HelpCircle, Monitor, Moon, Sun, User, X } from 'lucide-react';
import { XStack, YStack, SizableText as Text, ListItem, YGroup, Separator } from 'tamagui';
import { Pressable } from '@tamagui/react-native-web-lite';
import { ToggleGroup } from '@tamagui/toggle-group';
@@ -32,6 +32,12 @@ export function UserMenuSheet({ open, onClose, user, isMember, navigate }: UserM
}, [i18n.language]);
const themeValue: 'light' | 'dark' = (appearance === 'system' ? resolved : appearance) ?? 'light';
const selectedAppearance: 'light' | 'dark' | 'system' = appearance ?? 'system';
const resolvedLabel =
themeValue === 'dark'
? t('mobileProfile.themeDark', 'Dark')
: t('mobileProfile.themeLight', 'Light');
const systemLabel = t('mobileProfile.themeSystemLabel', 'System ({{mode}})', { mode: resolvedLabel });
const activeToggleBg = theme.accentSoft ?? withAlpha(theme.primary, 0.18);
const activeToggleBorder = withAlpha(theme.primary, 0.45);
@@ -244,9 +250,9 @@ export function UserMenuSheet({ open, onClose, user, isMember, navigate }: UserM
iconAfter={
<ToggleGroup
type="single"
value={themeValue}
value={selectedAppearance}
onValueChange={(next: string) => {
if (next === 'light' || next === 'dark') {
if (next === 'light' || next === 'dark' || next === 'system') {
updateAppearance(next);
}
}}
@@ -258,25 +264,24 @@ export function UserMenuSheet({ open, onClose, user, isMember, navigate }: UserM
{([
{ key: 'light', label: t('mobileProfile.themeLight', 'Light'), icon: Sun },
{ key: 'dark', label: t('mobileProfile.themeDark', 'Dark'), icon: Moon },
{ key: 'system', label: systemLabel, icon: Monitor },
] as const).map((option) => {
const active = option.key === themeValue;
const active = option.key === selectedAppearance;
const Icon = option.icon;
return (
<ToggleGroup.Item
key={option.key}
value={option.key}
aria-label={option.label}
borderRadius="$pill"
borderWidth={1}
borderColor={active ? activeToggleBorder : theme.border}
backgroundColor={active ? activeToggleBg : 'transparent'}
paddingHorizontal="$2.5"
paddingVertical="$1.5"
paddingHorizontal="$2"
paddingVertical="$1"
>
<XStack alignItems="center" gap="$1.5">
<Icon size={14} color={active ? theme.textStrong : theme.muted} />
<Text fontSize="$xs" fontWeight={active ? '700' : '600'} color={active ? theme.textStrong : theme.muted}>
{option.label}
</Text>
<XStack alignItems="center" justifyContent="center" minWidth={28} minHeight={24}>
<Icon size={16} color={active ? theme.textStrong : theme.muted} />
</XStack>
</ToggleGroup.Item>
);
@@ -288,7 +293,7 @@ export function UserMenuSheet({ open, onClose, user, isMember, navigate }: UserM
</YGroup>
{appearance === 'system' ? (
<Text fontSize="$xs" color={theme.muted}>
{t('mobileProfile.themeSystem', 'System')}
{t('mobileProfile.themeSystemHint', 'Following device setting: {{mode}}', { mode: resolvedLabel })}
</Text>
) : null}
</YStack>