124 lines
3.3 KiB
TypeScript
124 lines
3.3 KiB
TypeScript
import React from "react";
|
|
import {
|
|
View,
|
|
Modal,
|
|
Pressable,
|
|
ScrollView,
|
|
Dimensions,
|
|
StyleSheet,
|
|
} from "react-native";
|
|
import { Text } from "@/components/ui/text";
|
|
import { X, Check } from "@/lib/icons";
|
|
import { ShadowWrapper } from "@/components/ShadowWrapper";
|
|
import { useColorScheme } from "nativewind";
|
|
|
|
const { height: SCREEN_HEIGHT } = Dimensions.get("window");
|
|
|
|
interface PickerModalProps {
|
|
visible: boolean;
|
|
onClose: () => void;
|
|
title: string;
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
export function PickerModal({
|
|
visible,
|
|
onClose,
|
|
title,
|
|
children,
|
|
}: PickerModalProps) {
|
|
const { colorScheme } = useColorScheme();
|
|
const isDark = colorScheme === "dark";
|
|
|
|
return (
|
|
<Modal
|
|
visible={visible}
|
|
transparent
|
|
animationType="slide"
|
|
onRequestClose={onClose}
|
|
>
|
|
<Pressable className="flex-1 bg-black/40" onPress={onClose}>
|
|
<View className="flex-1 justify-end">
|
|
<Pressable
|
|
className="bg-card rounded-t-[36px] overflow-hidden border-t border-border/5"
|
|
style={{
|
|
maxHeight: SCREEN_HEIGHT * 0.8,
|
|
shadowColor: "#000",
|
|
shadowOffset: { width: 0, height: -10 },
|
|
shadowOpacity: 0.1,
|
|
shadowRadius: 20,
|
|
elevation: 20,
|
|
}}
|
|
onPress={(e) => e.stopPropagation()}
|
|
>
|
|
{/* Drag Handle */}
|
|
<View className="items-center pt-3 pb-1">
|
|
<View className="w-10 h-1 bg-border/20 rounded-full" />
|
|
</View>
|
|
|
|
{/* Header */}
|
|
<View className="px-6 pb-4 pt-2 flex-row justify-between items-center">
|
|
<View className="w-10" />
|
|
<Text variant="h4" className="text-foreground tracking-tight">
|
|
{title}
|
|
</Text>
|
|
<Pressable
|
|
onPress={onClose}
|
|
className="h-10 w-10 bg-secondary/80 rounded-full items-center justify-center border border-border/10"
|
|
>
|
|
<X
|
|
size={16}
|
|
color={isDark ? "#f1f5f9" : "#0f172a"}
|
|
strokeWidth={2.5}
|
|
/>
|
|
</Pressable>
|
|
</View>
|
|
|
|
<ScrollView
|
|
className="p-5 pt-0"
|
|
showsVerticalScrollIndicator={false}
|
|
contentContainerStyle={{ paddingBottom: 40 }}
|
|
>
|
|
{children}
|
|
</ScrollView>
|
|
</Pressable>
|
|
</View>
|
|
</Pressable>
|
|
</Modal>
|
|
);
|
|
}
|
|
|
|
export function SelectOption({
|
|
label,
|
|
value,
|
|
selected,
|
|
onSelect,
|
|
}: {
|
|
label: string;
|
|
value: string;
|
|
selected: boolean;
|
|
onSelect: (v: string) => void;
|
|
}) {
|
|
return (
|
|
<Pressable
|
|
onPress={() => onSelect(value)}
|
|
className={`flex-row items-center justify-between p-4 mb-3 rounded-[6px] border ${
|
|
selected
|
|
? "bg-primary/5 border-primary/20"
|
|
: "bg-secondary/20 border-border/5"
|
|
}`}
|
|
>
|
|
<Text
|
|
className={`font-bold text-[15px] ${selected ? "text-primary" : "text-foreground"}`}
|
|
>
|
|
{label}
|
|
</Text>
|
|
<View
|
|
className={`h-5 w-5 rounded-full items-center justify-center ${selected ? "bg-primary" : "border border-border/20"}`}
|
|
>
|
|
{selected && <Check size={12} color="white" strokeWidth={4} />}
|
|
</View>
|
|
</Pressable>
|
|
);
|
|
}
|