115 lines
5.3 KiB
TypeScript
115 lines
5.3 KiB
TypeScript
import React from 'react';
|
|
import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { useColors } from '../constants/Colors';
|
|
|
|
type ColorsType = ReturnType<typeof useColors>;
|
|
|
|
export type QuestionOption = { id: string; emoji: string; label: string; subtitle?: string };
|
|
|
|
type Props = {
|
|
colors: ColorsType;
|
|
isDarkMode: boolean;
|
|
step: number; // 1-based
|
|
totalSteps: number;
|
|
title: string;
|
|
subtitle: string;
|
|
options: QuestionOption[];
|
|
selectedId: string | null;
|
|
onSelect: (id: string) => void;
|
|
onContinue: () => void;
|
|
onBack?: () => void;
|
|
continueLabel: string;
|
|
skipLabel?: string;
|
|
onSkip?: () => void;
|
|
};
|
|
|
|
export function OnboardingQuestion({
|
|
colors, isDarkMode, step, totalSteps, title, subtitle, options,
|
|
selectedId, onSelect, onContinue, onBack, continueLabel, skipLabel, onSkip,
|
|
}: Props) {
|
|
return (
|
|
<SafeAreaView style={[styles.safe, { backgroundColor: isDarkMode ? '#0a110b' : '#f8fbef' }]} edges={['top', 'left', 'right', 'bottom']}>
|
|
<View style={styles.topBar}>
|
|
{onBack ? (
|
|
<TouchableOpacity onPress={onBack} style={[styles.backBtn, { backgroundColor: colors.surface }]}>
|
|
<Ionicons name="arrow-back" size={20} color={colors.primary} />
|
|
</TouchableOpacity>
|
|
) : <View style={styles.backBtn} />}
|
|
<View style={[styles.progressTrack, { backgroundColor: colors.primarySoft }]}>
|
|
<View style={[styles.progressFill, { backgroundColor: colors.primary, width: `${Math.round((step / totalSteps) * 100)}%` }]} />
|
|
</View>
|
|
<View style={styles.backBtn} />
|
|
</View>
|
|
{/* Scrollbar statt fixem Block: bei grosser Systemschriftgroesse wuchsen
|
|
Titel und Karten frueher ueber den Footer und haben den CTA verdeckt. */}
|
|
<ScrollView
|
|
style={styles.optionsScroll}
|
|
contentContainerStyle={styles.options}
|
|
showsVerticalScrollIndicator={false}
|
|
>
|
|
<Text style={[styles.title, { color: colors.text }]} maxFontSizeMultiplier={1.25}>{title}</Text>
|
|
<Text style={[styles.subtitle, { color: colors.textSecondary }]} maxFontSizeMultiplier={1.3}>{subtitle}</Text>
|
|
{options.map((option) => {
|
|
const active = selectedId === option.id;
|
|
return (
|
|
<TouchableOpacity
|
|
key={option.id}
|
|
onPress={() => onSelect(option.id)}
|
|
activeOpacity={0.85}
|
|
style={[styles.card, {
|
|
backgroundColor: active ? colors.primarySoft : colors.surface,
|
|
borderColor: active ? colors.primary : 'transparent',
|
|
}]}
|
|
>
|
|
<Text style={styles.emoji}>{option.emoji}</Text>
|
|
<View style={styles.cardCopy}>
|
|
<Text style={[styles.cardLabel, { color: active ? colors.primary : colors.text }]} maxFontSizeMultiplier={1.3}>{option.label}</Text>
|
|
{option.subtitle ? <Text style={[styles.cardSubtitle, { color: colors.textMuted }]} maxFontSizeMultiplier={1.3}>{option.subtitle}</Text> : null}
|
|
</View>
|
|
</TouchableOpacity>
|
|
);
|
|
})}
|
|
</ScrollView>
|
|
<View style={styles.footer}>
|
|
{skipLabel && onSkip ? (
|
|
<TouchableOpacity onPress={onSkip} style={styles.skipBtn}>
|
|
<Text style={[styles.skipText, { color: colors.textMuted }]}>{skipLabel}</Text>
|
|
</TouchableOpacity>
|
|
) : null}
|
|
<TouchableOpacity
|
|
onPress={onContinue}
|
|
disabled={!selectedId}
|
|
activeOpacity={0.86}
|
|
style={[styles.cta, { backgroundColor: selectedId ? colors.primary : colors.surfaceMuted }]}
|
|
>
|
|
<Text style={[styles.ctaText, { color: selectedId ? colors.onPrimary : colors.textMuted }]} maxFontSizeMultiplier={1.2}>{continueLabel}</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
safe: { flex: 1, paddingHorizontal: 22 },
|
|
topBar: { flexDirection: 'row', alignItems: 'center', gap: 14, paddingVertical: 10 },
|
|
backBtn: { width: 40, height: 40, borderRadius: 20, alignItems: 'center', justifyContent: 'center' },
|
|
progressTrack: { flex: 1, height: 6, borderRadius: 3, overflow: 'hidden' },
|
|
progressFill: { height: 6, borderRadius: 3 },
|
|
title: { fontSize: 30, lineHeight: 35, fontWeight: '900', textAlign: 'center', marginTop: 18, marginBottom: 8 },
|
|
subtitle: { fontSize: 15, lineHeight: 20, textAlign: 'center', marginBottom: 22 },
|
|
optionsScroll: { flex: 1 },
|
|
options: { gap: 12, paddingBottom: 12 },
|
|
card: { flexDirection: 'row', alignItems: 'center', gap: 14, borderRadius: 16, borderWidth: 2, paddingHorizontal: 16, paddingVertical: 18 },
|
|
emoji: { fontSize: 26 },
|
|
cardCopy: { flex: 1, gap: 2 },
|
|
cardLabel: { fontSize: 17, fontWeight: '800' },
|
|
cardSubtitle: { fontSize: 12.5, lineHeight: 16 },
|
|
footer: { gap: 8, paddingBottom: 6 },
|
|
skipBtn: { alignItems: 'center', paddingVertical: 6 },
|
|
skipText: { fontSize: 14, fontWeight: '700' },
|
|
cta: { minHeight: 56, paddingVertical: 16, borderRadius: 14, alignItems: 'center', justifyContent: 'center' },
|
|
ctaText: { fontSize: 17, fontWeight: '800' },
|
|
});
|