Rollback-Punkt vor Expo SDK 54 / RN 0.81 Upgrade. UI/UX: - Profile: ProfileHeader redesign (sign-in chip + member-since), StatsBar 3 pill cards, Demographics accordion completed (Geburtsjahr, Geschlecht, Familienstand, Beruf-split, Wohnort), Pro-Trial-Banner, Approved-Domains list, DigaMissionBanner - Settings: section-based layout, neutral icons (matched Header dropdown style) - Header dropdown: extended with logout + games-page link - Notifications page: skeleton dummy data - Locales: i18n keys for new screens New components: - WheelPickerModal: native iOS UIPickerView wheel for long lists (Geburtsjahr 91 items, Bundesland 16, Stadt 30+/Bundesland) - OptionsBottomSheet: iOS-style options sheet (used briefly for Geschlecht, currently unused — kept for potential future use) - germanCities.ts: Top-cities per Bundesland (DSGVO-clean static data) New libs (NewArch-codegen verified): - @react-native-menu/menu 2.0.0 (UIMenu wrapper, Apple HIG-konform) - @lodev09/react-native-true-sheet 3.10.1 (UISheetPresentationController wrapper — ABER incompatible mit RN 0.79.6, Build-Error → Trigger für SDK-54-Upgrade) Maestro E2E: - Initial setup mit auth/community/profile/urge flows Scripts: - build-ios-clean.sh: Xcode DerivedData + ios/build cleanup vor expo run:ios Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
82 lines
2.1 KiB
TypeScript
82 lines
2.1 KiB
TypeScript
// RN-Port der Vue-Card aus apps/rebreak/app/components/urge/UrgeGamePicker.vue
|
|
// 2x2-Grid-Kachel mit SVG-Icon (56x56), Titel, descKey und Star-Rating.
|
|
import { View, Text, Pressable } from 'react-native';
|
|
import { SvgXml } from 'react-native-svg';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { GameRatingStars } from './GameRatingStars';
|
|
import type { GameType } from '../urge/UrgeGames';
|
|
|
|
export interface GameCardProps {
|
|
id: GameType;
|
|
svg: string;
|
|
titleKey: string;
|
|
descKey: string;
|
|
avgStars: number;
|
|
count: number;
|
|
onPress: (id: GameType) => void;
|
|
}
|
|
|
|
export function GameCard({
|
|
id,
|
|
svg,
|
|
titleKey,
|
|
descKey,
|
|
avgStars,
|
|
count,
|
|
onPress,
|
|
}: GameCardProps) {
|
|
const { t } = useTranslation();
|
|
return (
|
|
<Pressable
|
|
onPress={() => onPress(id)}
|
|
style={({ pressed }) => ({
|
|
width: '100%',
|
|
transform: [{ scale: pressed ? 0.97 : 1 }],
|
|
opacity: pressed ? 0.85 : 1,
|
|
})}
|
|
>
|
|
<View style={{
|
|
borderRadius: 18,
|
|
borderWidth: 1,
|
|
borderColor: '#e5e7eb',
|
|
backgroundColor: '#fafafa',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
paddingVertical: 18,
|
|
paddingHorizontal: 12,
|
|
gap: 12,
|
|
}}>
|
|
<SvgXml xml={svg} width={56} height={56} />
|
|
<View style={{ alignItems: 'center', gap: 2 }}>
|
|
<Text
|
|
style={{
|
|
fontFamily: 'Nunito_700Bold',
|
|
color: '#0a0a0a',
|
|
fontSize: 15,
|
|
}}
|
|
>
|
|
{t(titleKey)}
|
|
</Text>
|
|
<Text
|
|
numberOfLines={2}
|
|
style={{
|
|
textAlign: 'center',
|
|
fontFamily: 'Nunito_400Regular',
|
|
color: '#737373',
|
|
fontSize: 11,
|
|
lineHeight: 14,
|
|
minHeight: 28,
|
|
paddingHorizontal: 4,
|
|
}}
|
|
>
|
|
{t(descKey)}
|
|
</Text>
|
|
<View style={{ marginTop: 4 }}>
|
|
<GameRatingStars avg={avgStars} count={count} />
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</Pressable>
|
|
);
|
|
}
|