Files
tbbank-react-native-mobile/src/components/SelectInput.js

163 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
Modal,
FlatList,
TouchableWithoutFeedback,
} from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { COLORS } from '../constants/colors';
/**
* SelectInput simple dropdown selector that mimics the look of Input component.
*
* Props:
* - label : string Field label
* - value : any Currently selected value
* - options : Array<{ label: string, value: any }>
* - onValueChange : (val) => void
* - placeholder : string Text when no value selected
* - disabled : boolean
*/
const SelectInput = ({
label,
value,
options = [],
onValueChange,
placeholder = 'Select',
disabled = false,
error = false,
}) => {
const [modalVisible, setModalVisible] = useState(false);
const selectedLabel = () => {
const found = options.find((o) => o.value === value);
return found ? found.label : placeholder;
};
const openModal = () => {
if (disabled) return;
setModalVisible(true);
};
const closeModal = () => setModalVisible(false);
const handleSelect = (val) => {
onValueChange && onValueChange(val);
closeModal();
};
return (
<View style={styles.container}>
{label && (
<Text style={[styles.label, typeof label === 'string' && label.trim().startsWith('*') && styles.requiredLabel]}>{label}</Text>
)}
<TouchableOpacity
style={[styles.selectBox, disabled && styles.disabled, error && styles.error]}
onPress={openModal}
activeOpacity={0.7}
>
<Text
style={[styles.selectText, !value && { color: COLORS.gray[400] }]}
numberOfLines={1}
>
{selectedLabel()}
</Text>
<Ionicons name="chevron-down" size={18} color={COLORS.gray[400]} />
</TouchableOpacity>
<Modal
animationType="slide"
transparent
visible={modalVisible}
onRequestClose={closeModal}
>
<TouchableWithoutFeedback onPress={closeModal}>
<View style={styles.modalOverlay}>
<TouchableWithoutFeedback>
<View style={styles.modalContainer}>
<FlatList
data={options}
keyExtractor={(item) => String(item.value)}
renderItem={({ item }) => (
<TouchableOpacity
style={styles.optionRow}
onPress={() => handleSelect(item.value)}
>
<Text style={styles.optionText}>{item.label}</Text>
</TouchableOpacity>
)}
/>
</View>
</TouchableWithoutFeedback>
</View>
</TouchableWithoutFeedback>
</Modal>
</View>
);
};
const styles = StyleSheet.create({
container: {
marginBottom: 20,
},
label: {
fontSize: 14,
fontWeight: '600',
color: COLORS.textPrimary,
marginBottom: 8,
},
requiredLabel: {
color: COLORS.error,
},
selectBox: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
borderWidth: 1,
borderColor: COLORS.gray[300],
borderRadius: 12,
backgroundColor: COLORS.white,
paddingHorizontal: 16,
minHeight: 52,
},
selectText: {
fontSize: 16,
color: COLORS.textPrimary,
flex: 1,
marginRight: 8,
},
disabled: {
backgroundColor: COLORS.gray[100],
opacity: 0.6,
},
error: {
borderColor: COLORS.error,
},
modalOverlay: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.3)',
justifyContent: 'center',
paddingHorizontal: 24,
},
modalContainer: {
backgroundColor: COLORS.white,
borderRadius: 12,
maxHeight: '70%',
},
optionRow: {
paddingVertical: 16,
paddingHorizontal: 20,
borderBottomWidth: 1,
borderBottomColor: COLORS.gray[200],
},
optionText: {
fontSize: 16,
color: COLORS.textPrimary,
},
});
export default SelectInput;