Untitled
unknown
typescript
5 months ago
4.0 kB
3
Indexable
import { Dispatch, SetStateAction, useEffect, useMemo, useRef, useState, } from "react" import { Roster } from "@/src/constants/Types" import { Button } from "react-native-paper" import { View, Text, Animated, FlatList, TouchableOpacity, StyleSheet, } from "react-native" import dayjs from "dayjs" import utc from "dayjs/plugin/utc" import timezone from "dayjs/plugin/timezone" import updateLocale from "dayjs/plugin/updateLocale" dayjs.extend(utc) dayjs.extend(timezone) dayjs.extend(updateLocale) dayjs.updateLocale("en", { weekStart: 1 }) export default function RosterPicker({ rosters, currentRoster, setCurrentRoster, }: { rosters: Roster[] currentRoster: Roster | null setCurrentRoster: Dispatch<SetStateAction<Roster | null>> }) { const [visible, setVisible] = useState<boolean>(false) const heightAnim = useRef(new Animated.Value(0)).current const toggleVisible = () => { setVisible((v) => !v) } const onItemPress = (roster: Roster) => { setCurrentRoster(roster) toggleVisible() } useEffect(() => { Animated.timing(heightAnim, { toValue: visible ? 200 : 0, duration: 300, useNativeDriver: false, }).start() // eslint-disable-next-line react-hooks/exhaustive-deps }, [visible]) const RenderItem = ({ item }: { item: Roster }) => { const isSelected = item.id === currentRoster?.id const backgroundColor = useMemo( () => (isSelected ? "#9f9f9f" : "#f9f9f9"), [isSelected] ) const textColor = useMemo( () => (isSelected ? "white" : "black"), [isSelected] ) return ( <Item item={item} onPress={() => onItemPress(item)} backgroundColor={backgroundColor} textColor={textColor} /> ) } return ( <View style={styles.container}> <Button mode="contained" onPress={toggleVisible} style={styles.button} contentStyle={styles.buttonContent} labelStyle={styles.buttonLabel} icon={visible ? "chevron-up" : "chevron-down"} > {formatRosterText(currentRoster)} </Button> <View style={styles.dropdownContainer}> <Animated.View style={[ styles.animatedView, { height: heightAnim, }, ]} > <FlatList data={rosters} renderItem={({ item }) => <RenderItem item={item} />} keyExtractor={(item) => item.id} extraData={currentRoster?.id} scrollEnabled={true} style={{ maxHeight: "100%", }} getItemLayout={(data, index) => ({ length: 50, // estimated row height offset: 50 * index, index, })} /> </Animated.View> </View> </View> ) } const styles = StyleSheet.create({ container: { width: "100%", alignItems: "center", padding: 3, }, button: { backgroundColor: "#aaa", borderRadius: 8, width: "auto", alignSelf: "flex-start", }, buttonContent: { gap: 4, flexDirection: "row-reverse", padding: 4, }, buttonLabel: { color: "rgba(0, 0, 0, 0.88)", }, dropdownContainer: { position: "relative", width: "100%", }, animatedView: { zIndex: 10, position: "absolute", marginTop: 1, backgroundColor: "white", borderRadius: 8, borderWidth: 1, borderColor: "#ccc", padding: 4, elevation: 2, // Android shadow shadowColor: "#000", // iOS shadow shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, shadowRadius: 4, }, }) type ItemProps = { item: Roster onPress: () => void backgroundColor: string textColor: string } const Item = ({ item, onPress, backgroundColor, textColor }: ItemProps) => ( <TouchableOpacity onPress={onPress} style={{ padding: 10, marginVertical: 4, marginLeft: 4, marginRight: 8, backgroundColor, }} > <Text style={{ fontSize: 16, color: textColor, }} > {formatRosterText(item)} </Text> </TouchableOpacity> ) const formatRosterText = (roster: Roster | null) => { if (!roster) return "No rosters" const start = roster.start.format("D MMM") const end = roster.end.format("D MMM") return start + " - " + end }
Editor is loading...
Leave a Comment