130 lines
3.5 KiB
TypeScript
130 lines
3.5 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
|
|
import { useAppTheme } from '../context/ThemeContext';
|
|
import { Feather } from '@expo/vector-icons';
|
|
import { Popup } from './Popup';
|
|
|
|
interface DropdownProps {
|
|
label?: string;
|
|
value: string;
|
|
options: string[];
|
|
onSelect: (val: string) => void;
|
|
required?: boolean;
|
|
infoText?: string;
|
|
placeholder?: string;
|
|
}
|
|
|
|
const LIME = '#C6F135';
|
|
|
|
export const Dropdown: React.FC<DropdownProps> = ({
|
|
label,
|
|
value,
|
|
options,
|
|
onSelect,
|
|
required = false,
|
|
infoText,
|
|
placeholder = 'Choose an option...'
|
|
}) => {
|
|
const { colors, isDark } = useAppTheme();
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
|
|
const bg = isDark ? '#1A1A1A' : '#F5F5F5';
|
|
const border = isDark ? '#2A2A2A' : '#EEEEEE';
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
{label && (
|
|
<View style={styles.labelRow}>
|
|
<Text style={[styles.label, { color: colors.textSecondary }]}>
|
|
{label}
|
|
{required ? <Text style={{ color: '#EF4444' }}> *</Text> : <Text style={{ color: isDark ? '#666' : '#CCC', fontSize: 10 }}> (Optional)</Text>}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
|
|
<TouchableOpacity
|
|
style={[styles.inputBox, { backgroundColor: bg, borderColor: border }]}
|
|
onPress={() => setIsOpen(true)}
|
|
>
|
|
<Text style={[styles.inputText, { color: value ? colors.text : (isDark ? '#444' : '#BBB') }]}>
|
|
{value || placeholder}
|
|
</Text>
|
|
<Feather name="chevron-down" size={18} color={isDark ? '#555' : '#AAA'} />
|
|
</TouchableOpacity>
|
|
|
|
{infoText && <Text style={[styles.infoText, { color: isDark ? '#6B6B6B' : '#9B9B9B' }]}>{infoText}</Text>}
|
|
|
|
<Popup visible={isOpen} onClose={() => setIsOpen(false)} title={`${label || 'Option'}`}>
|
|
<View style={styles.listContainer}>
|
|
{options.map((opt, idx) => (
|
|
<TouchableOpacity
|
|
key={idx}
|
|
style={[styles.optionItem, { borderBottomColor: border, borderBottomWidth: idx < options.length - 1 ? 1 : 0 }]}
|
|
onPress={() => {
|
|
onSelect(opt);
|
|
setIsOpen(false);
|
|
}}
|
|
>
|
|
<Text style={[styles.optionText, { color: colors.text, fontFamily: value === opt ? 'Outfit_700Bold' : 'Outfit_400Regular' }]}>
|
|
{opt}
|
|
</Text>
|
|
{value === opt && <Feather name="check-circle" size={18} color={LIME} />}
|
|
</TouchableOpacity>
|
|
))}
|
|
</View>
|
|
</Popup>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
marginBottom: 18,
|
|
width: '100%',
|
|
},
|
|
labelRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'flex-end',
|
|
marginBottom: 8,
|
|
},
|
|
label: {
|
|
fontSize: 11,
|
|
fontFamily: 'Outfit_700Bold',
|
|
letterSpacing: 1,
|
|
textTransform: 'uppercase',
|
|
},
|
|
inputBox: {
|
|
height: 56,
|
|
borderRadius: 14,
|
|
paddingHorizontal: 16,
|
|
borderWidth: 1.5,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
},
|
|
inputText: {
|
|
fontSize: 15,
|
|
fontFamily: 'Outfit_500Medium',
|
|
flex: 1,
|
|
},
|
|
infoText: {
|
|
fontSize: 12,
|
|
marginTop: 6,
|
|
marginLeft: 4,
|
|
fontFamily: 'Outfit_400Regular',
|
|
},
|
|
listContainer: {
|
|
paddingTop: 8,
|
|
},
|
|
optionItem: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
paddingVertical: 18,
|
|
},
|
|
optionText: {
|
|
fontSize: 15,
|
|
},
|
|
});
|