"use client"; import * as React from "react"; import { BottomSheetRoot, BottomSheetBackdrop, BottomSheetPositioner, BottomSheetContent, BottomSheetHeader, BottomSheetTitle, BottomSheetCloseButton, BottomSheetBody, TextFieldRoot, TextFieldInput, ListRoot, ListItem, Icon, } from "@seed-design/react"; import { useTransactions, todayLocalDate } from "@/api/hooks/reads"; import type { Txn } from "@/api/schemas"; import { tugrikRaw } from "@/ds/money"; import { assetsStrings as s } from "./strings"; const closeSvg = ( ); export interface TransactionPickerSheetProps { open: boolean; onOpenChange: (open: boolean) => void; /** "expense" for a new loan, "income" for a repayment — matches * `TransactionPickerView`'s direction filter on iOS. */ direction: "income" | "expense"; /** Transaction ids already linked to some loan/repayment, so already-linked * rows can carry a "Холбоотой" hint (mirrors `LendingModel.linkedTxnIds`). */ linkedTxnIds?: Set; onPick: (txn: Txn) => void; } /** * A searchable bottom sheet of the user's transactions, filtered to one * direction, for linking a lending entry or repayment to the real transaction * that created it. Ports `TransactionPickerView.swift` + `LendingAutofill.swift` * (the filtering/candidate logic lives inline below, small enough not to need * its own module). */ export function TransactionPickerSheet({ open, onOpenChange, direction, linkedTxnIds, onPick }: TransactionPickerSheetProps) { const [search, setSearch] = React.useState(""); // Pull ~1 year so older loans/repayments stay linkable, matching iOS. const from = React.useMemo(() => { const d = new Date(); d.setFullYear(d.getFullYear() - 1); return todayLocalDate(d); }, []); const to = React.useMemo(() => todayLocalDate(), []); const { data: transactions, isLoading } = useTransactions({ direction, from, to, limit: 500 }); const shown = React.useMemo(() => { const q = search.trim().toLowerCase(); return (transactions ?? []).filter((t) => { // Pending holds (no stable txnId) can't be linked. if (t.txnId == null || t.txnId === 0) return false; if (!q) return true; return t.title.toLowerCase().includes(q) || t.amount.toLowerCase().includes(q); }); }, [transactions, search]); return ( {s.lending.picker.title} {isLoading ? (

) : shown.length === 0 ? (

{s.lending.picker.empty}

) : ( {shown.map((txn) => { const linked = txn.txnId != null && linkedTxnIds?.has(txn.txnId); return ( ); })} )}
); }