132 lines
3.7 KiB
TypeScript
132 lines
3.7 KiB
TypeScript
import React from 'react';
|
|
import { View, StyleSheet, TouchableOpacity, ScrollView, Text, Platform, useWindowDimensions } from 'react-native';
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
import { OnboardingColors, OnboardingFont } from '@/constants/OnboardingTheme';
|
|
import BtnNotClicked from '@/assets/images/icon/btn_Notclicked.svg';
|
|
import BtnClicked from '@/assets/images/icon/btn_clicked.svg';
|
|
|
|
interface Option {
|
|
id: string;
|
|
label: string;
|
|
}
|
|
|
|
interface SelectionStepProps {
|
|
options: Option[];
|
|
selectedIds: string[];
|
|
onToggle: (id: string) => void;
|
|
onNext: () => void;
|
|
onSkip?: () => void;
|
|
}
|
|
|
|
export function SelectionStep({ options, selectedIds, onToggle, onNext, onSkip }: SelectionStepProps) {
|
|
const { width, height } = useWindowDimensions();
|
|
const isTablet = Platform.OS === 'ios' && Math.min(width, height) >= 768;
|
|
const maxOptionWidth = isTablet ? 560 : undefined;
|
|
const hasSelection = selectedIds.length > 0;
|
|
const insets = useSafeAreaInsets();
|
|
const footerBottom = insets.bottom + (isTablet ? 38 : 28);
|
|
const footerButtonHeight = 57;
|
|
// 底部留白加大,避免最后一项与按钮边框视觉重叠
|
|
const footerPaddingBottom = footerBottom + footerButtonHeight + 40;
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<ScrollView
|
|
style={styles.scroll}
|
|
showsVerticalScrollIndicator={false}
|
|
contentContainerStyle={[
|
|
styles.optionsList,
|
|
{
|
|
paddingBottom: footerPaddingBottom,
|
|
alignItems: 'center',
|
|
},
|
|
]}
|
|
>
|
|
{options.map((option) => {
|
|
const isSelected = selectedIds.includes(option.id);
|
|
return (
|
|
<TouchableOpacity
|
|
key={option.id}
|
|
style={[
|
|
styles.optionCard,
|
|
maxOptionWidth ? { maxWidth: maxOptionWidth } : null,
|
|
isSelected && styles.optionCardSelected,
|
|
]}
|
|
onPress={() => onToggle(option.id)}
|
|
activeOpacity={0.7}
|
|
>
|
|
<Text style={styles.optionText}>{option.label}</Text>
|
|
</TouchableOpacity>
|
|
);
|
|
})}
|
|
</ScrollView>
|
|
|
|
{/* 底部按钮:距离底部 12% 高度 */}
|
|
<View style={[styles.footer, { bottom: footerBottom }]}>
|
|
<TouchableOpacity onPress={onNext} disabled={!hasSelection} activeOpacity={0.8}>
|
|
{hasSelection ? <BtnClicked width={87} height={57} /> : <BtnNotClicked width={87} height={57} />}
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
paddingTop: 8,
|
|
},
|
|
scroll: {
|
|
flex: 1,
|
|
},
|
|
optionsList: {
|
|
// paddingBottom 由安全区 + 按钮高度动态计算,避免选项被遮住
|
|
},
|
|
optionCard: {
|
|
width: '100%',
|
|
height: 75,
|
|
backgroundColor: OnboardingColors.cardBackground,
|
|
borderRadius: 20,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
paddingHorizontal: 24,
|
|
marginBottom: 12,
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 2 },
|
|
shadowOpacity: 0.05,
|
|
shadowRadius: 10,
|
|
elevation: 2,
|
|
},
|
|
optionCardSelected: {
|
|
backgroundColor: OnboardingColors.cardSelected,
|
|
},
|
|
optionText: {
|
|
fontSize: 18,
|
|
color: OnboardingColors.textPrimary,
|
|
fontWeight: '500',
|
|
fontFamily: OnboardingFont.question,
|
|
},
|
|
footer: {
|
|
position: 'absolute',
|
|
left: 0,
|
|
right: 0,
|
|
alignItems: 'center',
|
|
},
|
|
footerRow: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 16,
|
|
},
|
|
skipBtn: {
|
|
paddingVertical: 10,
|
|
paddingHorizontal: 14,
|
|
borderRadius: 12,
|
|
backgroundColor: 'rgba(0,0,0,0.04)',
|
|
},
|
|
skipText: {
|
|
fontSize: 16,
|
|
color: OnboardingColors.textMuted,
|
|
},
|
|
});
|