"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 (
);
})}
)}
);
}