Untitled

 avatar
unknown
typescript
5 months ago
3.8 kB
2
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,
	FlatList,
	TouchableOpacity,
	StyleSheet,
	Animated,
} 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 [isOpen, setIsOpen] = useState(false)
	const heightAnim = useRef(new Animated.Value(0)).current

	const toggleVisible = () => {
		setIsOpen(!isOpen)
	}

	const onItemPress = (roster: Roster) => {
		setCurrentRoster(roster)
		toggleVisible()
	}

	useEffect(() => {
		Animated.timing(heightAnim, {
			toValue: isOpen ? 175: 0,
			duration: 200,
			useNativeDriver: false,
		}).start()
	}, [heightAnim, isOpen])

	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={isOpen ? "chevron-up" : "chevron-down"}
			>
				{formatRosterText(currentRoster)}
			</Button>
			<View style={styles.dropdownContainer}>
				<Animated.View
					style={[
						styles.animatedView,
						{
							height: heightAnim,
						},
					]}
				>
					<View style={styles.listContainer}>
						<FlatList
							data={rosters}
							renderItem={({ item }) => (
								<RenderItem item={item} />
							)}
							keyExtractor={(item) => item.id.toString()}
							extraData={currentRoster?.id}
						/>
					</View>
				</Animated.View>
			</View>
		</View>
	)
}

const styles = StyleSheet.create({
	container: {
		width: "auto",
		alignSelf: "flex-end",
		padding: 3,
		zIndex: 10,
	},
	dropdownContainer: {
		position: "relative",
	},
	animatedView: {
		position: "absolute",
		overflow: "hidden",
		marginTop: 1,
		width: "100%",
	},
	listContainer: {
		padding: 4,
		backgroundColor: "white",
		borderRadius: 8,
		borderWidth: 1,
		borderColor: "#ccc",
		elevation: 2, // Android shadow
		shadowColor: "#000", // iOS shadow
		shadowOffset: { width: 0, height: 2 },
		shadowOpacity: 0.2,
		shadowRadius: 4,
	},
	button: {
		backgroundColor: "#aaa",
		borderRadius: 8,
	},
	buttonContent: {
		gap: 4,
		flexDirection: "row-reverse",
		padding: 4,
	},
	buttonLabel: {
		color: "rgba(0, 0, 0, 0.88)",
	},
})

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={{
				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