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 { 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; readOnly?: boolean; isLast?: boolean; }; export function LineItemsTableHeader() { const { colors } = useAppTheme(); return ( Description Date Hrs Rate Amt ); } export function LineItemEditor({ item, index, currency, onChange, onRemove, 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 ( {index + 1} {item.description.trim() || "Untitled line"} {formatShortDate(item.date)} · {hours}h × {formatCurrency(rate, currency)} {formatCurrency(amount, currency)} ); } return ( {index + 1} onChange({ description })} placeholder="What was done?" placeholderTextColor={colors.mutedForeground} style={[ styles.descriptionInput, { color: colors.foreground, borderColor: colors.border, backgroundColor: colors.cardGlass, }, ]} /> onChange({ date })} style={styles.dateField} /> onChange({ hours })} step={0.25} style={styles.hoursField} /> $ onChange({ rate })} keyboardType="decimal-pad" placeholder="0" placeholderTextColor={colors.mutedForeground} style={[styles.rateInput, { color: colors.foreground }]} /> {formatCurrency(amount, currency)} [styles.remove, pressed && styles.removePressed]} > ); } const headerStyles = StyleSheet.create({ row: { flexDirection: "row", alignItems: "center", gap: spacing.xs, paddingBottom: spacing.xs, marginBottom: spacing.xs, borderBottomWidth: 1, }, cell: { fontFamily: fonts.bodySemiBold, fontSize: 11, textTransform: "uppercase", letterSpacing: 0.4, }, desc: { flex: 1, paddingLeft: 22 }, date: { width: 72 }, hours: { width: 88, textAlign: "center" }, rate: { width: 72, textAlign: "center" }, amt: { width: 64, textAlign: "right" }, spacer: { width: 32 }, }); const styles = StyleSheet.create({ row: { flexDirection: "row", alignItems: "center", gap: spacing.xs, paddingVertical: spacing.sm, }, editBlock: { paddingVertical: spacing.sm, gap: spacing.xs, }, editTop: { flexDirection: "row", alignItems: "center", gap: spacing.xs, }, index: { width: 18, fontFamily: fonts.bodySemiBold, fontSize: 12, textAlign: "center", }, descCol: { flex: 1, gap: 2, }, readTitle: { fontFamily: fonts.bodyMedium, fontSize: 14, lineHeight: 18, }, readSub: { fontFamily: fonts.body, fontSize: 11, }, descriptionInput: { flex: 1, minHeight: 36, borderWidth: 1, borderRadius: radii.md, paddingHorizontal: spacing.sm, fontFamily: fonts.body, fontSize: 14, paddingVertical: 6, }, metricsRow: { flexDirection: "row", alignItems: "center", gap: spacing.xs, paddingLeft: 22, }, dateField: { width: 72, }, hoursField: { width: 88, }, rateField: { width: 72, flexDirection: "row", alignItems: "center", borderWidth: 1, borderRadius: radii.md, minHeight: 36, paddingHorizontal: spacing.xs, }, ratePrefix: { fontFamily: fonts.body, fontSize: 13, }, rateInput: { flex: 1, fontFamily: fonts.body, fontSize: 13, paddingVertical: 4, textAlign: "right", }, amount: { width: 64, fontFamily: fonts.bodySemiBold, fontSize: 13, textAlign: "right", }, amountEdit: { fontSize: 12, }, remove: { width: 32, height: 36, alignItems: "center", justifyContent: "center", }, removePressed: { opacity: 0.65, }, });