"use client"; import { Coins, EllipsisVertical, HandCoins, Pencil, PiggyBank, Plus, Trash2 } from "lucide-react"; import Link from "next/link"; import { useEffect, useState } from "react"; import { toast } from "sonner"; import { MoneyInput } from "@/components/money-input"; import { ResponsiveDialog } from "@/components/responsive-dialog"; import { AlertDialog, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Badge } from "@/components/ui/badge"; import { Checkbox } from "@/components/ui/checkbox"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Field, FieldDescription, FieldError, FieldGroup, FieldLabel } from "@/components/ui/field"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { getAssetOptionsAction, type AssetOption } from "@/features/assets/actions"; import { getTransactionFormOptionsAction } from "@/features/transactions/actions"; import { AccountSelect } from "@/features/transactions/components/transaction-form"; import type { TransactionFormOptions } from "@/features/transactions/service"; import { tr } from "@/i18n/tr"; import { cn } from "@/lib/utils"; import { ASSET_KEYS, ASSETS, formatAssetQuantity, type AssetKey } from "@/shared/assets"; import { todayIstanbul } from "@/shared/dates"; import { formatDate, formatMoney } from "@/shared/format"; import { formatMoneyInput } from "@/shared/money"; import { QUANTITY_SCALE } from "@/shared/quantity"; import { addContributionAction, deleteInKindAction, recordPaymentAction, saveInKindAction, } from "../actions"; import type { InKindView } from "../service"; const t = tr.inKind; type Errors = Record; const d = (ymd: string) => formatDate(`${ymd}T12:00:00+03:00`); const monthFmt = new Intl.DateTimeFormat("tr-TR", { month: "long", year: "numeric", timeZone: "Europe/Istanbul", }); const qtyInput = (q: number) => (q / QUANTITY_SCALE).toLocaleString("tr-TR", { maximumFractionDigits: 3, useGrouping: false }); /** Hesap seçenekleri (diyaloglar açıldığında). */ export function useAccounts() { const [options, setOptions] = useState(null); useEffect(() => { let cancelled = false; getTransactionFormOptionsAction().then((r) => { if (!cancelled && r.ok) setOptions(r.data); }); return () => { cancelled = true; }; }, []); return options?.accounts ?? null; } /** Kaydın varlık türündeki birikim varlıkları (ödeme diyaloğu açıldığında). */ function useAssetOptions(assetKey: AssetKey) { const [options, setOptions] = useState(null); useEffect(() => { let cancelled = false; getAssetOptionsAction().then((r) => { if (!cancelled && r.ok) setOptions(r.data.filter((a) => a.assetKey === assetKey)); }); return () => { cancelled = true; }; }, [assetKey]); return options; } function Stat({ label, value, tone }: { label: string; value: string; tone?: string }) { return (

{label}

{value}

); } type Pending = | { kind: "form"; item: InKindView | null } | { kind: "contribute"; item: InKindView } | { kind: "pay"; item: InKindView } | { kind: "delete"; item: InKindView } | null; /** Cari sayfasında aynî borç/alacak bölümü. */ export function InKindSection({ contactId, items, canWrite, }: { contactId: string; items: InKindView[]; canWrite: boolean; }) { const [pending, setPending] = useState(null); const close = () => setPending(null); return (

{t.title}

{t.description}

{canWrite ? ( ) : null}
{items.map((item) => ( ))} {pending?.kind === "form" ? ( ) : null} {pending?.kind === "contribute" ? ( ) : null} {pending?.kind === "pay" ? : null} !o && close()}> {t.deleteTitle} {t.deleteDescription} {tr.common.cancel}
); } function InKindCard({ item, canWrite, onAction, }: { item: InKindView; canWrite: boolean; onAction: (p: Pending) => void; }) { const p = item.progress; const debt = item.direction === "debt"; const open = !item.closedAt; return (
{item.label} {t.directions[item.direction]} {item.closedAt ? ( {t.stats.closed(d(item.closedAt))} ) : null} {t.stats.dateValue(d(item.date))}:{" "} {item.valueMinor !== null ? formatMoney(item.valueMinor) : "—"} {item.unitPriceMinor !== null ? ` · ${t.stats.priceAt(formatMoney(item.unitPriceMinor), d(item.date))}` : ""}
{canWrite ? ( onAction({ kind: "form", item })}> {tr.common.edit} onAction({ kind: "delete", item })} > {t.delete} ) : null}
{item.savingsAccount ? ( <> ) : null}
{p.estimatedCloseMonth && open ? (

{t.stats.estimatedClose}:{" "} {monthFmt.format(new Date(`${p.estimatedCloseMonth}-15T12:00:00+03:00`))} {item.monthlyPlanMinor ? ( {" "} · {formatMoney(item.monthlyPlanMinor)}/ay ) : null}

) : null} {item.currentPrice ? (

{t.stats.currentPrice( debt, formatMoney(debt ? item.currentPrice.sellMinor : item.currentPrice.buyMinor), d(item.currentPrice.date), )}

) : null} {item.note ?

{item.note}

: null} {item.payments.length ? (

{t.payments}

    {item.payments.map((x) => (
  • {d(x.date)} ·{" "} {t.paymentLine( t.methods[x.method], formatAssetQuantity(item.assetKey, x.quantity), x.amountMinor ? formatMoney(x.amountMinor) : null, )} {x.account ? ( {x.account} ) : null}
  • ))}
) : null} {canWrite && open ? (
{debt && item.savingsAccount ? ( ) : null}
) : null}
); } function Footer({ busy, formId, onClose }: { busy: boolean; formId: string; onClose: () => void }) { return ( <> ); } function InKindForm({ contactId, item, onClose, }: { contactId: string; item: InKindView | null; onClose: () => void; }) { const accounts = useAccounts(); const [v, setV] = useState({ direction: item?.direction ?? "debt", assetKey: (item?.assetKey ?? "gram_gold") as AssetKey, quantity: item ? qtyInput(item.quantity) : "", date: item?.date ?? todayIstanbul(), unitPrice: item?.unitPriceMinor ? formatMoneyInput(item.unitPriceMinor) : "", note: item?.note ?? "", savingsAccountId: item?.savingsAccount?.id ?? "", monthlyPlan: item?.monthlyPlanMinor ? formatMoneyInput(item.monthlyPlanMinor) : "", }); const [errors, setErrors] = useState({}); const [busy, setBusy] = useState(false); const set = (k: K, x: (typeof v)[K]) => setV((s) => ({ ...s, [k]: x })); const NONE = "__none__"; async function submit(e: React.FormEvent) { e.preventDefault(); setBusy(true); const r = await saveInKindAction(contactId, item?.id ?? null, { ...v, savingsAccountId: v.direction === "debt" ? v.savingsAccountId : "", monthlyPlan: v.direction === "debt" && v.savingsAccountId ? v.monthlyPlan : "", }); setBusy(false); if (r.ok) { toast.success(t.toast.saved); onClose(); } else setErrors({ ...r.fieldErrors, root: r.fieldErrors ? undefined : r.error }); } const f = t.fields; return ( !o && onClose()} title={item ? t.editTitle : t.createTitle} footer={