import { Ionicons } from "@expo/vector-icons"; import { Pressable, StyleSheet, Text, TextInput, View } from "react-native"; import { CompactDateField } from "@/components/ui/CompactDateField"; import { CompactStepperInput } from "@/components/ui/CompactStepperInput"; import { SwipeableRow } from "@/components/SwipeableRow"; import { fonts, radii, spacing } from "@/constants/theme"; import { useAppTheme } from "@/contexts/ThemeContext"; import { formatCurrency, formatShortDate } from "@/lib/format"; export type EditableLineItem = { id?: string; date: Date; description: string; hours: string; rate: string; }; type LineItemEditorProps = { item: EditableLineItem; index: number; currency: string; onChange: (patch: Partial) => void; onRemove: () => void; onDuplicate?: () => void; readOnly?: boolean; isLast?: boolean; }; function FieldLabel({ children }: { children: string }) { const { colors } = useAppTheme(); return ( {children} ); } export function LineItemEditor({ item, index, currency, onChange, onRemove, onDuplicate, readOnly = false, isLast = false, }: LineItemEditorProps) { const { colors } = useAppTheme(); const hours = Number(item.hours) || 0; const rate = Number(item.rate) || 0; const amount = hours * rate; if (readOnly) { return ( Line {index + 1} {item.description.trim() || "Untitled line"} {formatShortDate(item.date)} · {hours}h × {formatCurrency(rate, currency)} {formatCurrency(amount, currency)} ); } const content = ( Line {index + 1} onChange({ description })} placeholder="What was done?" placeholderTextColor={colors.mutedForeground} style={[ styles.descriptionInput, { color: colors.foreground, borderColor: colors.border, backgroundColor: colors.cardGlass, }, ]} /> Date onChange({ date })} style={styles.fieldControl} /> Hours onChange({ hours })} step={0.25} style={styles.fieldControl} /> Rate $ onChange({ rate })} keyboardType="decimal-pad" placeholder="0" placeholderTextColor={colors.mutedForeground} style={[styles.rateInput, { color: colors.foreground }]} /> Amount {formatCurrency(amount, currency)} [ styles.remove, { borderColor: colors.border, backgroundColor: colors.cardGlass }, pressed && styles.removePressed, ]} > ); const swipeActions = [ ...(onDuplicate ? [ { key: "duplicate", label: "Copy", icon: "copy-outline" as const, color: "#fff", backgroundColor: colors.primary, onPress: onDuplicate, }, ] : []), { key: "delete", label: "Delete", icon: "trash-outline" as const, color: "#fff", backgroundColor: colors.destructive, onPress: onRemove, }, ]; return ( {content} ); } const styles = StyleSheet.create({ readBlock: { paddingVertical: spacing.md, gap: spacing.xs, }, readIndex: { fontFamily: fonts.bodySemiBold, fontSize: 11, textTransform: "uppercase", letterSpacing: 0.4, }, readTitle: { fontFamily: fonts.bodyMedium, fontSize: 15, lineHeight: 20, }, readSub: { fontFamily: fonts.body, fontSize: 13, }, readAmount: { fontFamily: fonts.bodySemiBold, fontSize: 15, marginTop: 2, }, editBlock: { paddingVertical: spacing.md, gap: spacing.sm, }, lineLabel: { fontFamily: fonts.bodySemiBold, fontSize: 11, textTransform: "uppercase", letterSpacing: 0.4, }, descriptionInput: { width: "100%", minHeight: 40, borderWidth: 1, borderRadius: radii.md, paddingHorizontal: spacing.sm, fontFamily: fonts.body, fontSize: 15, paddingVertical: 8, }, fieldsRow: { flexDirection: "row", gap: spacing.sm, }, fieldCol: { flex: 1, gap: 4, minWidth: 0, }, fieldLabel: { fontFamily: fonts.bodyMedium, fontSize: 11, textTransform: "uppercase", letterSpacing: 0.3, }, fieldControl: { width: "100%", }, rateField: { minHeight: 36, flexDirection: "row", alignItems: "center", borderWidth: 1, borderRadius: radii.md, paddingHorizontal: spacing.xs, }, ratePrefix: { fontFamily: fonts.body, fontSize: 13, }, rateInput: { flex: 1, fontFamily: fonts.bodyMedium, fontSize: 13, paddingVertical: 4, textAlign: "right", minWidth: 0, }, footerRow: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", gap: spacing.sm, marginTop: 2, }, amountGroup: { flex: 1, flexDirection: "row", alignItems: "baseline", gap: spacing.sm, }, amountLabel: { fontFamily: fonts.bodyMedium, fontSize: 12, textTransform: "uppercase", letterSpacing: 0.3, }, amountValue: { fontFamily: fonts.bodySemiBold, fontSize: 17, }, remove: { width: 40, height: 40, borderRadius: radii.md, borderWidth: 1, alignItems: "center", justifyContent: "center", }, removePressed: { opacity: 0.65, }, });