import { useLocalSearchParams, useRouter } from "expo-router"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { ActivityIndicator, Alert, Pressable, ScrollView, Text, TextInput, View, } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Ionicons } from "@expo/vector-icons"; import { useSettlementV2 } from "@/src/hooks/useFixedCosts"; import { useHouseholdSettings } from "@/src/hooks/useHouseholdSettings"; import { useCloseMonth } from "@/src/hooks/useMonthStatus"; import { useAuthStore } from "@/src/stores/auth.store"; import { monthLabel } from "@/src/utils/date"; import { formatEur } from "@/src/utils/format"; const ACCENT = "#2563EB"; export default function CloseMonthScreen() { const insets = useSafeAreaInsets(); const router = useRouter(); const { t } = useTranslation(); const { month } = useLocalSearchParams<{ month: string }>(); const userId = useAuthStore((s) => s.user?.id); const { data: settlement, isLoading: settlementLoading } = useSettlementV2(month); const { data: hhSettings } = useHouseholdSettings(); const { mutate: closeMonth, isPending } = useCloseMonth(month); const remaining = settlement?.remaining ?? 0; const [amountStr, setAmountStr] = useState(null); const [notes, setNotes] = useState(""); // Lazy-init amount from settlement once loaded const displayAmount = amountStr ?? (remaining > 0 ? remaining.toFixed(2).replace(".", ",") : "0,00"); const others = (settlement?.members ?? []).filter((m) => m.userId !== userId); const otherName = hhSettings?.partnerName ?? others[0]?.name ?? "Partner"; const otherUserId = others[0]?.userId ?? ""; function handleAmountChange(text: string) { // Allow only digits and one comma const cleaned = text.replace(/[^0-9,]/g, ""); const parts = cleaned.split(","); if (parts.length > 2) return; if (parts[1] !== undefined && parts[1].length > 2) return; setAmountStr(cleaned); } function handleClose() { const amount = parseFloat(displayAmount.replace(",", ".")) || 0; Alert.alert( t('monthClose.closeConfirmTitle', { month: monthLabel(month) }), t('monthClose.closeConfirmMessage'), [ { text: t('common.cancel'), style: "cancel" }, { text: t('monthClose.closeConfirmAction'), style: "destructive", onPress: () => { closeMonth( { finalAmount: amount, toUserId: otherUserId, notes: notes.trim() || undefined }, { onSuccess: () => router.back(), onError: (err) => Alert.alert(t('common.error'), err.message ?? "Abschluss fehlgeschlagen"), }, ); }, }, ], ); } if (settlementLoading) { return ( ); } const s = settlement; return ( {/* Header */} router.back()} className="mr-3 p-1"> {t('monthClose.title', { month: monthLabel(month) })} {/* Overview card */} {s && ( {t('monthClose.overview')} {s.householdIncome > 0 && ( )} 0 ? Math.round(100 / s.memberCount) : 50 })} value={`-${formatEur(s.perMemberShare)}`} bold /> {s.lineItems.length > 0 && ( <> {s.lineItems.map((li) => ( ))} )} )} {/* Remaining amount hero */} 0.01 ? "#fff7ed" : "#f0fdf4", borderWidth: 1, borderColor: remaining > 0.01 ? "#fed7aa" : "#bbf7d0" }} > {remaining > 0.01 ? t('monthClose.receives', { name: otherName }) : remaining < -0.01 ? t('monthClose.youReceive') : t('monthClose.settled')} 0.01 ? "#ea580c" : remaining < -0.01 ? "#16a34a" : "#6b7280" }} > {formatEur(Math.abs(remaining))} {/* Amount adjustment */} {t('monthClose.adjustAmount')} {t('monthClose.adjustHint')} {/* Notes */} {t('monthClose.note')} {/* CTA */} {isPending ? ( ) : ( {t('monthClose.closeButton')} )} router.back()} className="py-3 items-center active:opacity-50" > {t('common.cancel')} ); } function Row({ label, value, bold, color, }: { label: string; value: string; bold?: boolean; color?: string; }) { return ( {label} {value} ); }