This repository has been archived on 2026-08-17. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
beenvoice-app/components/ui/CompactDateField.tsx
T
soconnorandCursor 355b14faef Add local iOS release pipeline, fix shortcuts, and improve invoice UX.
Enable App Store builds without EAS, iOS 18 App Intents plugins, and signing
fixes for distribution export. Add mobile invoice PDF preview, compact line
items, and more reliable shortcut deep-link handling.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-23 01:08:20 -04:00

175 lines
4.6 KiB
TypeScript

import DateTimePicker, {
type DateTimePickerEvent,
} from "@react-native-community/datetimepicker";
import { Ionicons } from "@expo/vector-icons";
import { useState } from "react";
import {
Modal,
Platform,
Pressable,
StyleSheet,
Text,
View,
type StyleProp,
type ViewStyle,
} from "react-native";
import { fonts, radii } from "@/constants/theme";
import { useAppTheme } from "@/contexts/ThemeContext";
import { formatShortDate } from "@/lib/format";
type CompactDateFieldProps = {
value: Date;
onChange: (date: Date) => void;
style?: StyleProp<ViewStyle>;
maximumDate?: Date;
minimumDate?: Date;
};
export function CompactDateField({
value,
onChange,
style,
maximumDate = new Date(2100, 0, 1),
minimumDate,
}: CompactDateFieldProps) {
const { colors, isDark } = useAppTheme();
const [open, setOpen] = useState(false);
const [draft, setDraft] = useState(value);
function applyDate(next: Date) {
const clamped =
next.getTime() > maximumDate.getTime()
? maximumDate
: minimumDate && next.getTime() < minimumDate.getTime()
? minimumDate
: next;
onChange(clamped);
}
function handleChange(event: DateTimePickerEvent, selected?: Date) {
if (Platform.OS === "android") {
setOpen(false);
if (event.type === "set" && selected) applyDate(selected);
return;
}
if (selected) setDraft(selected);
}
return (
<>
<Pressable
accessibilityRole="button"
accessibilityLabel="Change date"
onPress={() => {
setDraft(value);
setOpen(true);
}}
style={({ pressed }) => [
styles.trigger,
{
borderColor: colors.border,
backgroundColor: colors.cardGlass,
},
pressed && styles.pressed,
style,
]}
>
<Text style={[styles.value, { color: colors.foreground }]} numberOfLines={1}>
{formatShortDate(value)}
</Text>
<Ionicons name="chevron-down" size={12} color={colors.mutedForeground} />
</Pressable>
{Platform.OS === "ios" ? (
<Modal visible={open} transparent animationType="slide" onRequestClose={() => setOpen(false)}>
<Pressable style={styles.backdrop} onPress={() => setOpen(false)}>
<Pressable
style={[styles.sheet, { backgroundColor: colors.card }]}
onPress={(event) => event.stopPropagation()}
>
<View style={[styles.sheetHeader, { borderBottomColor: colors.border }]}>
<Pressable onPress={() => setOpen(false)}>
<Text style={[styles.action, { color: colors.mutedForeground }]}>Cancel</Text>
</Pressable>
<Text style={[styles.sheetTitle, { color: colors.foreground }]}>Date</Text>
<Pressable
onPress={() => {
applyDate(draft);
setOpen(false);
}}
>
<Text style={[styles.action, { color: colors.primary }]}>Done</Text>
</Pressable>
</View>
<DateTimePicker
value={draft}
mode="date"
display="spinner"
maximumDate={maximumDate}
minimumDate={minimumDate}
themeVariant={isDark ? "dark" : "light"}
onChange={handleChange}
/>
</Pressable>
</Pressable>
</Modal>
) : open ? (
<DateTimePicker
value={draft}
mode="date"
maximumDate={maximumDate}
minimumDate={minimumDate}
onChange={handleChange}
/>
) : null}
</>
);
}
const styles = StyleSheet.create({
trigger: {
minHeight: 36,
borderWidth: 1,
borderRadius: radii.md,
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingHorizontal: 8,
gap: 2,
},
pressed: {
opacity: 0.9,
},
value: {
flex: 1,
fontFamily: fonts.body,
fontSize: 12,
},
backdrop: {
flex: 1,
justifyContent: "flex-end",
backgroundColor: "rgba(0,0,0,0.45)",
},
sheet: {
borderTopLeftRadius: radii.lg,
borderTopRightRadius: radii.lg,
},
sheetHeader: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingHorizontal: 16,
paddingVertical: 12,
borderBottomWidth: 1,
},
sheetTitle: {
fontFamily: fonts.bodySemiBold,
fontSize: 15,
},
action: {
fontFamily: fonts.bodyMedium,
fontSize: 15,
},
});