PageSourceSearch

https://landledger.co/assets/AdminLoans-DImbw0pF.js

js landledger.co collected 2026-10-04 06:56:01 UTC 50,623 bytes, 11 lines download raw bytes

1import{f as Pe,k as Je,r as h,d as Y,b as A,t as y,j as e,B as f,a as Q,R as $,q as Te,u as Ze,s as Ye,x as ee,T as se,n as te,o as ae}from"./index-CudHG6B4.js";import{u as E}from"./useMutation-CBAYgnG2.js";import{A as es}from"./AdminLayout-BZuCIv3f.js";import{E as ss}from"./BackingDashboard-CVY4Rsg2.js";import{B as w}from"./badge-CMf0SrHQ.js";import{I as T}from"./input-kx1YXBs7.js";import{L as S}from"./label-B2onvOiF.js";import{T as Ae,a as Le,b as K,c as b,d as De,e as v}from"./table-Hzp9xhRa.js";import{C as ts,e as as,S as rs,a as ns,b as is,c as ls,d as cs}from"./InstitutionRegister-CdUSyHyq.js";import{A as Fe,a as Ue,b as $e,c as Re,d as Ie,e as Ee,f as Me,g as Be}from"./alert-dialog-BT3erKQG.js";import{C as M,b as X,c as G,d as ue,a as B}from"./card-5b9UOcPu.js";import{A as Oe,b as ze}from"./alert-kp6gCZ70.js";import{T as ds,a as os,b as ie,c as le}from"./tabs-CZVTTJLT.js";import{C as ms,a as xs,b as us}from"./collapsible-DIiF-mf5.js";import{S as _e,M as hs}from"./skeleton-BegiI0pz.js";import{D as qe,g as He,h as Ve,i as We,j as Ke,k as oe}from"./AuthenticatedApplication-C2-e6xTS.js";import{L as ps}from"./LoanCompliancePanel-CXoZw0LW.js";import{T as js}from"./textarea-C9FUOvKW.js";import{P as fs}from"./plus-B9dTNDWs.js";import{C as ne}from"./circle-check-CTosiqnS.js";import{C as gs}from"./clock-3-D4RumAKQ.js";import{f as J}from"./format-ClYrW1qG.js";import{L as Ns}from"./layers-Ca3pv70P.js";import{i as je}from"./isPast-ChzaWx0D.js";import{a as Qe}from"./chevron-up-qSRaMRim.js";import{C as ys}from"./chevron-right-Dr8cwl4J.js";import{C as vs}from"./circle-alert-CRUc3mQk.js";import{C as bs}from"./clock-DzjvzExH.js";import{P as Xe}from"./play-BCM8PPR6.js";import{E as fe}from"./eye-uFk1fLjc.js";import{C as ws}from"./circle-x-BHDARfrW.js";import{T as Ss}from"./triangle-alert-BA2tGhup.js";import{T as ge}from"./trash-2-B1etNceJ.js";import{E as Cs}from"./shield-Hr0aqzVI.js";import{U as ks}from"./user-DCnI1kiW.js";import{L as Ps}from"./ProtocolPage-UaH8jgc9.js";import{L as Ts}from"./lock-open-Dxkt8JIW.js";import{S as Ne}from"./shield-alert-DI2v-8Md.js";import{A as As}from"./arrow-right-left-BDk_ZO7Q.js";import"./arrow-left-lxn-dpfG.js";import"./dollar-sign-BcfyEtLy.js";import"./index-C1iJF-SR.js";import"./check-D8BjNWtW.js";import"./building-2-CMfa6c9V.js";import"./shield-check-ic92rXB7.js";import"./users-DX1W4CCh.js";import"./connectors-BciFpN0c.js";import"./circle-C1ccQMbh.js";import"./file-text-76AiIfll.js";import"./AboutPage-CamkJ7cK.js";import"./PrivacyPage-Beavwhs0.js";import"./TermsPage-SeBMfIpe.js";import"./LandVerifyPage-NEwI3vUf.js";import"./award-BusU1ju6.js";import"./hash-DyzAXdJv.js";import"./globe-NLl4Wr5a.js";import"./scale-DM0tAT-O.js";import"./calendar-BTBtzozc.js";import"./trending-up-C66B21n6.js";import"./landmark-BA_0Cnnl.js";import"./LandCertificate-Du_3NAH9.js";import"./printer-C2HCk7DD.js";import"./OnchainDocsPage-DDA6342p.js";import"./book-open-DvSukaGG.js";import"./code-CMLileHq.js";import"./sprout-z_rucUaP.js";import"./TransparencyPage-Ylxz21fu.js";import"./LandProtocolDevRef-_yp8P5Ot.js";import"./InstitutionInvitePage-CIc8kA4i.js";import"./FlowOfFundsPage-BjbpHgzo.js";import"./CapitalProviderChoice-C78InrEx.js";import"./arrow-right-B1UlrPw0.js";import"./IndividualProviderRegister-DyWPKEYx.js";import"./documentUpload-DQeSb8US.js";import"./download-CjAU_iCB.js";/**
2 * @license lucide-react v0.469.0 - ISC
3 *
4 * This source code is licensed under the ISC license.
5 * See the LICENSE file in the root directory of this source tree.
6 */const me=Pe("ArrowDown",[["path",{d:"M12 5v14",key:"s699le"}],["path",{d:"m19 12-7 7-7-7",key:"1idqje"}]]);/**
7 * @license lucide-react v0.469.0 - ISC
8 *
9 * This source code is licensed under the ISC license.
10 * See the LICENSE file in the root directory of this source tree.
11 */const xe=Pe("ArrowUp",[["path",{d:"m5 12 7-7 7 7",key:"hav0vg"}],["path",{d:"M12 19V5",key:"x0mq9r"}]]),re=s=>`$${(Number(s)/1e6).toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2})}`,ye=s=>s.replace(/_/g," "),_=(s,n=!0)=>{const[o,c,r]=s.slice(0,10).split("-").map(Number),l=new Date(Date.UTC(o,c-1,r));return new Intl.DateTimeFormat("en-US",{timeZone:"UTC",month:"short",day:"numeric",...n?{year:"numeric"}:{}}).format(l)};function Ls(s){if(!s)return{segments:null,error:"Segment evidence is not available for this legacy record."};try{const n=JSON.parse(s);return!Array.isArray(n)||n.some(o=>{if(!o||typeof o!="object")return!0;const c=o;return typeof c.start!="string"||typeof c.end!="string"||typeof c.days!="number"||typeof c.outstandingPrincipalMicroUsd!="str
11ing"})?{segments:null,error:"Segment evidence has an unexpected structure."}:{segments:n,error:null}}catch{return{segments:null,error:"Segment evidence could not be read; the accrual remains available for reconciliation."}}}function Ds({loanId:s}){var he,pe;const n=Je(),[o,c]=h.useState(!1),[r,l]=h.useState("approve"),[m,d]=h.useState(null),[u,x]=h.useState(""),[i,p]=h.useState(""),[j,t]=h.useState(""),[N,C]=h.useState(""),[L,k]=h.useState(""),[P,O]=h.useState(""),z=[`/api/admin/v2/loans/${s}/broker-servicing-accruals`],D=Y({queryKey:z}),q=()=>n.invalidateQueries({queryKey:z}),H=!!u&&!!i&&new Date(i).getTime()>new Date(u).getTime(),R=E({mutationFn:async()=>(await A("POST",`/api/admin/v2/loans/${s}/broker-servicing-accruals/calculate`,{periodStart:u,periodEnd:i})).json(),onSuccess:()=>{y.success("Servicing accrual calculated."),x(""),p(""),q()},onError:a=>y.error(a.message)}),g=E({mutationFn:async()=>{if(!m||!j.trim())throw new Error("A reconciliation reason is required.");const a={reason:j.trim()};if(r==="adjust"){if(!N.trim()||!L.trim())throw new Error("Adjustment amount and correction key are required.");a.adjustmentMicroUsd=N.trim(),a.correctionKey=L.trim()}if(r==="pay"){if(!P.trim())throw new Error("A manual payout reference is required.");a.payoutReference=P.trim()}return(await A("POST",`/api/admin/v2/loans/${s}/broker-servicing-accruals/${m.id}/${r}`,a)).json()},onSuccess:()=>{y.success("Accrual reconciliation saved."),c(!1),t(""),C(""),k(""),O(""),q()},onError:a=>y.error(a.message)}),V=(a,I)=>{d(a),l(I),t(""),C(""),k(""),O(""),c(!0)};return e.jsxs(M,{children:[e.jsxs(X,{className:"pb-3",children:[e.jsx(G,{className:"text-base",children:"Broker servicing accruals"}),e.jsx(ue,{children:"Calculate and reconcile the manual broker servicing ledger. No payout is executed automatically."})]}),e.jsxs(B,{className:"space-y-4",children:[e.jsxs("div",{className:"rounded-md border border-dashed p-3",children:[e.jsxs("div",{className:"mb-2 flex items-center gap-2 text-sm font-semibold",children:[e.jsx(fs,{className:"h-4 w-4"}),"Calculate a period"]}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:items-end",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(S,{htmlFor:`accrual-start-${s}`,children:"Period start"}),e.jsx(T,{id:`accrual-start-${s}`,type:"date",value:u,onChange:a=>x(a.target.value)})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(S,{htmlFor:`accrual-end-${s}`,children:"Period end"}),e.jsx(T,{id:`accrual-end-${s}`,type:"date",value:i,onChange:a=>p(a.target.value)}),u&&i&&!H&&e.jsx("p",{className:"text-xs text-destructive",children:"End must be after start."})]}),e.jsxs(f,{disabled:!H||R.isPending,onClick:()=>R.mutate(),children:[R.isPending&&e.jsx(Q,{className:"mr-1 h-4 w-4 animate-spin"}),"Calculate"]})]})]}),D.isLoading?e.jsx("div",{className:"h-20 animate-pulse rounded-md bg-muted"}):D.isError?e.jsxs("div",{className:"flex items-center justify-between rounded-md border border-destructive/20 bg-destructive/5 p-3 text-sm text-destructive",children:[e.jsx("span",{children:"Accrual history could not be loaded."}),e.jsx(f,{size:"sm",variant:"outline",onClick:()=>D.refetch(),children:"Retry"})]}):(((he=D.data)==null?void 0:he.accruals.length)??0)===0?e.jsx("p",{className:"rounded-md bg-muted/50 p-3 text-sm text-muted-foreground",children:"No servicing periods have been calculated."}):e.jsx("div",{className:"space-y-2",children:(pe=D.data)==null?void 0:pe.accruals.map(a=>{const I=Ls(a.segmentSnapshot);return e.jsxs("div",{className:"rounded-md border p-3",children:[e.jsxs("div",{className:"flex flex-col justify-between gap-2 sm:flex-row sm:items-start",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("span",{className:"font-semibold text-sm",children:[_(a.periodStart)," – ",_(a.periodEnd)]}),e.jsx(w,{variant:a.status==="paid"?"secondary":a.status==="held"?"destructive":"outline",className:"capitalize",children:ye(a.status)})]}),e.jsxs("p",{className:"mt-1 text-xs text-muted-foreground",children:[a.daysElapsed," days · ",a.annualBrokerServicingBps," bps · opening principal ",re(a.outstandingPrincipalMicroUsd)," · re
11corded ",J(new Date(a.createdAt),"MMM d, yyyy")]})]}),e.jsx("strong",{className:"tabular-nums",children:re(a.amountMicroUsd)})]}),a.adjustmentReason&&e.jsxs("p",{className:"mt-2 text-xs text-muted-foreground",children:["Lifecycle / adjustment reason: ",a.adjustmentReason]}),(a.status==="approved"||a.status==="held")&&(a.reconciliationNote||a.reconciledByUserId!==null||a.reconciledServicingSpreadPayoutId!==null)&&e.jsxs("div",{className:"mt-2 rounded border bg-muted/30 p-2 text-xs",children:[e.jsx("p",{className:"font-semibold",children:"Staff reconciliation evidence"}),a.reconciliationNote&&e.jsxs("p",{children:["Note: ",a.reconciliationNote]}),a.reconciledByUserId!==null&&e.jsxs("p",{children:["Reconciler user ID: ",a.reconciledByUserId]}),a.reconciledServicingSpreadPayoutId!==null&&e.jsxs("p",{children:["Linked servicing payout ID: ",a.reconciledServicingSpreadPayoutId]})]}),a.status==="paid"&&e.jsxs("div",{className:"mt-2 rounded border border-emerald-200 bg-emerald-50/60 p-2 text-xs text-emerald-950",children:[e.jsx("p",{className:"font-semibold",children:"Staff-only payment reconciliation"}),e.jsxs("p",{children:["Payout reference: ",a.payoutReference||"Not recorded"]}),e.jsxs("p",{children:["Paid: ",a.paidAt?J(new Date(a.paidAt),"MMM d, yyyy h:mm a"):"Not recorded"]}),e.jsxs("p",{children:["Reconciliation note: ",a.reconciliationNote||"Not recorded"]}),e.jsxs("p",{children:["Reconciler user ID: ",a.reconciledByUserId??"Not recorded"]}),a.reconciledServicingSpreadPayoutId!==null&&e.jsxs("p",{children:["Linked servicing payout ID: ",a.reconciledServicingSpreadPayoutId]})]}),I.error?e.jsx("p",{className:"mt-2 rounded border border-amber-200 bg-amber-50/60 p-2 text-xs text-amber-950",children:I.error}):I.segments&&e.jsxs("details",{className:"mt-2",children:[e.jsxs("summary",{className:"cursor-pointer text-xs font-semibold text-muted-foreground",children:["Segment breakdown (",I.segments.length,")"]}),e.jsx("div",{className:"mt-2 space-y-1 border-l pl-3",children:I.segments.map((W,Ge)=>e.jsxs("div",{className:"flex flex-wrap justify-between gap-x-3 gap-y-1 text-xs",children:[e.jsxs("span",{children:[_(W.start,!1)," – ",_(W.end)," · ",W.days," days"]}),e.jsx("strong",{children:re(W.outstandingPrincipalMicroUsd)})]},`${W.start}-${Ge}`))})]}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[a.status==="accrued"&&e.jsxs(e.Fragment,{children:[e.jsxs(f,{size:"sm",onClick:()=>V(a,"approve"),children:[e.jsx(ne,{className:"mr-1 h-3.5 w-3.5"}),"Approve"]}),e.jsxs(f,{size:"sm",variant:"outline",onClick:()=>V(a,"hold"),children:[e.jsx(gs,{className:"mr-1 h-3.5 w-3.5"}),"Hold"]})]}),a.status==="held"&&e.jsx(f,{size:"sm",variant:"outline",onClick:()=>V(a,"approve"),children:"Release to approve"}),(a.status==="accrued"||a.status==="held"||a.status==="approved")&&e.jsx(f,{size:"sm",variant:"outline",onClick:()=>V(a,"adjust"),children:"Adjust"}),a.status==="approved"&&e.jsx(f,{size:"sm",variant:"outline",onClick:()=>V(a,"pay"),children:"Record manual payment"})]})]},a.id)})})]}),e.jsx(qe,{open:o,onOpenChange:c,children:e.jsxs(He,{children:[e.jsxs(Ve,{children:[e.jsxs(We,{children:[ye(r)," accrual"]}),e.jsx(Ke,{children:r==="pay"?"Record the external payout after it has been executed manually.":"This decision is recorded in the audit ledger."})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"rounded-md bg-muted p-3 text-sm",children:[e.jsx("strong",{children:m&&re(m.amountMicroUsd)})," · ",m&&_(m.periodStart,!1)," – ",m&&_(m.periodEnd)]}),r==="adjust"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(S,{htmlFor:"adjustment-amount",children:"Adjustment (micro-USD)"}),e.jsx(T,{id:"adjustment-amount",value:N,onChange:a=>C(a.target.value),placeholder:"For example, -125000"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(S,{htmlFor:"correction-key",children:"Correction key"}),e.jsx(T,{id:"correction-key",value:L,onChange:a=>k(a.target.value)})]})]}),r==="pay"&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(S,{htmlFor:"payout-reference",children:"Manual payout reference"}),e.jsx(T,{id:"payout-reference",value:P,onChange:a=>O(a.target.value)})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(S,{htmlFor:"reconciliation-reason",children:"Reason"}),e.jsx(js,{id:"reconciliation-reason",value:j,onChange:a=>t(a.target.value),placeholder:"Explain the servicing decision"})]})]}),e.jsxs(oe,{children:[e.jsx(f,{variant:"outline",onClick:()=>c(!1),children:"Cancel"}),e.jsxs(f,{disabled:g.isPending||!j.trim(),onClick:()=>g.mutate(),children:[g.isPending&&e.jsx(Q,{className:"mr-1 h-4 w-4 animate-spin"}),"Save reconciliation"]})]})]})})]})}const Fs={A:"text-emerald-700 bg-emerald-50 border-emerald-200",B:"text-blue-700 bg-blue-50 border-blue-200",C:"text-amber-700 bg-amber-50 border-amber-200",D:"text-orange-700 bg-orange-50 border-orange-200",E:"text-red-700 bg-red-50 border-red-200"};function F(s){if(s==null)return"N/A";const n=typeof s=="string"?parseFloat(s):s;
11return isNaN(n)?"N/A":"$"+n.toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2})}function ve({distribution:s}){return e.jsx("div",{className:"rounded-md border overflow-x-auto",children:e.jsxs(Ae,{children:[e.jsx(Le,{children:e.jsxs(K,{children:[e.jsx(b,{className:"w-20",children:"Tranche"}),e.jsx(b,{className:"text-right text-xs",children:"Scheduled Interest"}),e.jsx(b,{className:"text-right text-xs",children:"Interest Paid"}),e.jsx(b,{className:"text-right text-xs",children:"Principal"}),e.jsx(b,{className:"text-right text-xs",children:"Total Paid"}),e.jsx(b,{className:"text-right text-xs",children:"New Balance"})]})}),e.jsx(De,{children:s.map(n=>{const o=Fs[n.trancheLetter]??"text-gray-700 bg-gray-50 border-gray-200",c=!!n.tokenId,r=parseFloat(n.interestUsd)<parseFloat(n.scheduledInterestUsd??"0");return e.jsxs(K,{className:c?"":"opacity-50",children:[e.jsx(v,{children:e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-semibold border ${o}`,children:n.trancheLetter}),!c&&e.jsx("span",{className:"text-xs text-muted-foreground",children:"(no token)"})]})}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:F(n.scheduledInterestUsd)}),e.jsxs(v,{className:`text-right font-mono text-xs ${r?"text-amber-600 font-semibold":""}`,children:[F(n.interestUsd),r&&e.jsx("span",{className:"block text-xs text-amber-500",children:"shorted"})]}),e.jsx(v,{className:"text-right font-mono text-xs",children:F(n.principalUsd)}),e.jsx(v,{className:"text-right font-mono text-xs font-semibold",children:F(n.totalUsd)}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:F(n.newCurrentPrincipalUsd)})]},n.participationId)})})]})})}function Us({loan:s,payment:n,paymentIndex:o,open:c,onClose:r}){const l=parseFloat(n.amountUsd),m=(l*.9).toFixed(2),d=(l*.1).toFixed(2),[u,x]=h.useState(m),[i,p]=h.useState(m),[j,t]=h.useState(d),[N,C]=h.useState(n.paymentType==="balloon"),[L,k]=h.useState(null),[P,O]=h.useState(null),z=E({mutationFn:async()=>(await A("POST",`/api/admin/v2/loans/${s.id}/process-payment`,{paymentId:n.id,scheduledInterestAmountUsd:parseFloat(u).toFixed(2),interestAmountUsd:parseFloat(i).toFixed(2),principalAmountUsd:parseFloat(j).toFixed(2),finalPayment:N,dryRun:!0})).json(),onSuccess:g=>k(g),onError:g=>y.error("Preview failed",{description:String(g)})}),D=E({mutationFn:async()=>(await A("POST",`/api/admin/v2/loans/${s.id}/process-payment`,{paymentId:n.id,scheduledInterestAmountUsd:parseFloat(u).toFixed(2),interestAmountUsd:parseFloat(i).toFixed(2),principalAmountUsd:parseFloat(j).toFixed(2),finalPayment:N,dryRun:!1})).json(),onSuccess:g=>{O(g),y.success("Payment processed",{description:`Tx: ${g.servicerTxHash.slice(0,10)}...`}),Te.invalidateQueries({queryKey:["/api/admin/v2/loans",s.id,"payments"]})},onError:g=>y.error("Payment failed",{description:String(g)})}),q=(parseFloat(i||"0")+parseFloat(j||"0")).toFixed(2),H=!isNaN(parseFloat(u))&&!isNaN(parseFloat(i))&&!isNaN(parseFloat(j))&&parseFloat(u)>=0&&parseFloat(i)>=0&&parseFloat(j)>=0&&parseFloat(q)>0;function R(){k(null),O(null),x(m),p(m),t(d),C(n.paymentType==="balloon"),r()}return e.jsx(qe,{open:c,onOpenChange:g=>!g&&R(),children:e.jsxs(He,{className:"max-w-2xl max-h-[90vh] overflow-y-auto",children:[e.jsxs(Ve,{children:[e.jsxs(We,{children:["Process Payment ",o+1," - Loan ",s.loanNumber??s.landName??""]}),e.jsxs(Ke,{children:["Scheduled: ",F(n.amountUsd)," due ",J(new Date(n.dueDate),"MMM d, yyyy"),s.landName&&` - ${s.landName}`]})]}),P?e.jsxs("div",{className:"space-y-4",children:[e.jsxs(Oe,{className:"border-[#009955]/30 bg-[#009955]/5",children:[e.jsx(ne,{className:"h-4 w-4 text-[#009955]"}),e.jsxs(ze,{children:["Payment processed on-chain. Tx: ",e.jsx("span",{className:"font-mono text-xs",children:P.servicerTxHash})]})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium mb-2",children:"Waterfall distribution applied:"}),e.jsx(ve,{distribution:P.distribution})]}),e.jsxs("div",{className:"flex gap-2 text-xs text-muted-foreground",children:[e.jsx(me,{className:"h-3 w-3 mt-0.5 text-emerald-600 flex-shrink-0"}),e.jsx("span",{children:"Interest paid A first (senior priority)"}),e.jsx("span",{className:"mx-1",children:"|"}),e.jsx(xe,{className:"h-3 w-3 mt-0.5 text-red-500 flex-shrink-0"}),e.jsx("span",{children:"Principal reduced E first (junior priority)"})]}),e.jsx(oe,{children:e.jsx(f,{onClick:R,children:"Close"})})]}):e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(S,{htmlFor:"sched-interest-amt",children:"Scheduled interest owed this period (USD)"}),e.jsx(T,{id:"sched-interest-amt",type:"number",min:"0",step:"0.01",value:u,onChange:g=>{x(g.target.value),k(null)}}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"What each tranche is owed for this period. Used to compute per-tranche entitlements independent of the actual payment. For full payments, set equal to actual interest paid."})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(S,{htmlFor:"interest-amt",children:"Actual interest paid (USD)"}),e.jsx(T,{id:"interest-amt",type:"number",min:"0",step:"0.01",value:i,onChange:g=>{p(g.target.value),k(null)}}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Distributed A first. May be less than scheduled for partial payments."})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(S,{htmlFor:"principal-amt",children:"Principal reduction (USD)"}),e.jsx(T,{id:"principal-amt",type:"number",min:"0",step:"0.01",value:j,onChange:g=>{t(g.target.value),k(null)}}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Distributed E first (junior repays first)"})]})]}),e.jsxs("div",{className:"flex items-center justify-between rounded-md border p-3 text-sm",children:[e.jsx("span",{className:"text-muted-foreground",children:"Total actual payment"}),e.jsx("span",{className:"font-semibold tabular-nums",children:F(q)})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ts,{id:"final-payment",checked:N,onCheckedChange:g=>C(!!g)}),e.jsx(S,{htmlFor:"final-payment",className:"text-sm cursor-pointer",children:"Final payment (marks tokens STATUS_PAID_OFF on-chain)"})]}),L&&e.jsxs("div",{className:"space-y-2",children:[e.jsx(as,{}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(fe,{className:"h-4 w-4 text-muted-foreground"}),e.jsx("p",{className:"text-sm font-medium",children:"Waterfall preview (dry-run)"})]}),e.jsx(ve,{distribution:L.distribution}),e.jsxs("div",{className:"flex flex-wrap gap-4 text-xs text-muted-foreground pt-1",children:[e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(me,{className:"h-3 w-3 text-emerald-600"}),"Interest: A receives first, then B, C, D, E"]}),e.jsxs("span",{className:"flex items-center gap-1",children:[e.jsx(xe,{className:"h-3 w-3 text-red-500"}),"Principal: E repaid first, then D, C, B, A"]})]})]}),e.jsxs(oe,{className:"gap-2 flex-wrap",children:[e.jsx(f,{variant:"outline",onClick:R,children:"Cancel"}),e.jsxs(f,{variant:"outline",disabled:!H||z.isPending,onClick:()=>z.mutate(),children:[z.isPending?e.jsx(Q,{className:"h-4 w-4 animate-spin mr-1"}):e.jsx(fe,{className:"h-4 w-4 mr-1"}),"Preview Waterfall"]}),e.jsxs(f,{disabled:!L||!H||D.isPending,onClick:()=>D.mutate(),children:[D.isPending?e.jsx(Q,{className:"h-4 w-4 animate-spin mr-1"}):e.jsx(Xe,{className:"h-4 w-4 mr-1"}),"Confirm and Process"]})]})]})]})})}function be({loan:s}){const[n,o]=h.useState(!1),[c,r]=h.useState(null),{data:l=[],isLoading:m}=Y({queryKey:["/api/admin/v2/loans",s.id,"payments"],queryFn:async()=>{const i=await fetch(`/api/v2/loans/${s.id}/payments`,{credentials:"include"});
11return i.ok?i.json():[]},enabled:n}),d=l.filter(i=>i.status==="scheduled").length,u=l.filter(i=>i.status==="paid").length,x=l.filter(i=>i.status==="scheduled"&&je(new Date(i.dueDate))).length;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-start gap-3 p-4 border rounded-lg cursor-pointer hover:bg-muted/30 transition-colors",onClick:()=>o(i=>!i),children:[e.jsx("div",{className:"mt-0.5 text-muted-foreground",children:n?e.jsx(Qe,{className:"h-4 w-4"}):e.jsx(ys,{className:"h-4 w-4"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2 mb-1",children:[e.jsxs("span",{className:"font-semibold text-sm",children:["Loan ",s.loanNumber??s.landName??""]}),s.landName&&e.jsx("span",{className:"text-sm text-muted-foreground truncate max-w-[200px]",children:s.landName}),e.jsx(w,{variant:s.status==="active"?"default":"secondary",className:"text-xs",children:s.status})]}),e.jsxs("div",{className:"flex flex-wrap gap-4 text-xs text-muted-foreground",children:[e.jsxs("span",{children:["Principal: ",e.jsx("strong",{children:F(s.totalPrincipalUsd)})]}),e.jsxs("span",{children:["Rate: ",e.jsxs("strong",{children:[(s.blendedRateBps/100).toFixed(2),"%"]})]}),e.jsxs("span",{children:["Term: ",e.jsxs("strong",{children:[s.termMonths,"mo"]})]}),s.borrowerEmail&&e.jsxs("span",{children:["Borrower: ",e.jsx("strong",{children:s.borrowerEmail})]}),e.jsxs("span",{children:["Tranches: ",e.jsx("strong",{children:s.participationCount})]})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2 text-xs shrink-0",children:[x>0&&e.jsxs(w,{variant:"destructive",className:"text-xs",children:[x," overdue"]}),d>0&&e.jsxs("span",{className:"text-muted-foreground",children:[d," scheduled"]}),u>0&&e.jsxs("span",{className:"text-[#009955]",children:[u," paid"]})]})]}),n&&e.jsxs("div",{className:"ml-7 space-y-1.5 border-l-2 border-border pl-4 mt-1",children:[["active","delinquent","defaulted"].includes(s.status)&&e.jsx(ps,{loanId:s.id,mode:"staff"}),["active","delinquent","defaulted"].includes(s.status)&&e.jsx(Ds,{loanId:s.id}),m?e.jsx(_e,{className:"h-10 w-full"}):l.length===0?e.jsx("p",{className:"text-xs text-muted-foreground py-2",children:"No payment schedule found."}):l.map((i,p)=>{const j=i.status==="scheduled"&&je(new Date(i.dueDate)),t=i.status==="paid"||i.status==="waived",N=!t&&s.participationCount>0;return e.jsxs("div",{className:`flex items-center justify-between px-3 py-2 rounded-md border text-sm ${t?"border-[#009955]/20 bg-[#009955]/5":j?"border-destructive/30 bg-destructive/5":"border-border bg-background"}`,children:[e.jsxs("div",{className:"flex items-center gap-2.5",children:[t?e.jsx(ne,{className:"h-3.5 w-3.5 text-[#009955] flex-shrink-0"}):j?e.jsx(vs,{className:"h-3.5 w-3.5 text-destructive flex-shrink-0"}):e.jsx(bs,{className:"h-3.5 w-3.5 text-muted-foreground flex-shrink-0"}),e.jsxs("div",{children:[e.jsxs("p",{className:"font-medium text-xs",children:["Payment ",p+1,i.paymentType==="balloon"&&e.jsx("span",{className:"ml-1 text-muted-foreground",children:"(balloon)"})]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[t&&i.paidDate?`Paid ${J(new Date(i.paidDate),"MMM d, yyyy")}`:`Due ${J(new Date(i.dueDate),"MMM d, yyyy")}`,j&&" (overdue)"]})]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{className:"text-right",children:[e.jsx("p",{className:`font-semibold text-xs tabular-nums ${t?"text-[#009955]":j?"text-destructive":""}`,children:F(i.paidAmountUsd??i.amountUsd)}),i.txHash&&e.jsxs("p",{className:"text-xs text-muted-foreground font-mono",children:[i.txHash.slice(0,8),"..."]})]}),N&&e.jsxs(f,{size:"sm",variant:j?"destructive":"outline",className:"text-xs h-7 px-2.5",onClick:C=>{C.stopPropagation(),r({payment:i,index:p})},children:[e.jsx(Xe,{className:"h-3 w-3 mr-1"}),t?"Re-process":"Process"]})]})]},i.id)})]}),c&&e.jsx(Us,{loan:s,payment:c.payment,paymentIndex:c.index,open:!!c,onClose:()=>r(null)})]})}function $s(){const{data:s=[],isLoading:n,refetch:o}=Y({queryKey:["/api/admin/v2/loans"],queryFn:async()=>{const l=await fetch("/api/admin/v2/loans",{credentials:"include"});if(!l.ok)throw new Error("Failed to load loans");return l.json()}}),c=s.filter(l=>
11["active","pending_disbursement"].includes(l.status)),r=s.filter(l=>!["active","pending_disbursement"].includes(l.status));return e.jsx("div",{children:e.jsxs("div",{className:"max-w-4xl mx-auto py-8 px-4 space-y-6",children:[e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{children:[e.jsxs("h1",{className:"text-2xl font-bold flex items-center gap-2",children:[e.jsx(Ns,{className:"h-6 w-6 text-[#009955]"}),"Loan Servicing"]}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"Process borrower payments with waterfall enforcement. Interest distributed A first, principal reduced E first."})]}),e.jsxs(f,{variant:"outline",size:"sm",onClick:()=>o(),children:[e.jsx($,{className:"h-4 w-4 mr-1.5"}),"Refresh"]})]}),e.jsx(M,{className:"border-[#009955]/20 bg-[#009955]/5",children:e.jsx(B,{className:"pt-4 pb-4",children:e.jsxs("div",{className:"flex flex-wrap gap-6 text-sm",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(me,{className:"h-4 w-4 text-emerald-600"}),e.jsxs("span",{children:[e.jsx("strong",{children:"Interest waterfall:"})," Tranche A receives first, then B, C, D, E (senior priority)"]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(xe,{className:"h-4 w-4 text-red-500"}),e.jsxs("span",{children:[e.jsx("strong",{children:"Principal waterfall:"})," Tranche E repaid first, then D, C, B, A (junior repays first)"]})]})]})})}),n?e.jsx("div",{className:"space-y-3",children:[1,2,3].map(l=>e.jsx(_e,{className:"h-20 w-full"},l))}):s.length===0?e.jsx(M,{children:e.jsx(B,{className:"py-12 text-center text-muted-foreground",children:"No v2 loans found."})}):e.jsxs("div",{className:"space-y-6",children:[c.length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs("h2",{className:"text-sm font-semibold text-muted-foreground uppercase tracking-wide",children:["Active Loans (",c.length,")"]}),e.jsx("div",{className:"space-y-2",children:c.map(l=>e.jsx(be,{loan:l},l.id))})]}),r.length>0&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs("h2",{className:"text-sm font-semibold text-muted-foreground uppercase tracking-wide",children:["Other Loans (",r.length,")"]}),e.jsx("div",{className:"space-y-2",children:r.map(l=>e.jsx(be,{loan:l},l.id))})]})]})]})})}const Rs={pending_admin:"bg-amber-100 text-amber-700",approved:"bg-emerald-100 text-emerald-700",rejected:"bg-red-100 text-red-700"};function we(s){return`$${parseFloat(s).toLocaleString(void 0,{minimumFractionDigits:0})}`}function ce(s){return`${(s/100).toFixed(2)}%`}function Se(s,n){return`$${(parseFloat(s)*(n/1e4)).toFixed(2)}`}function Is(){const{data:s,isLoading:n,refetch:o}=Y({queryKey:["/api/admin/secondary-market/trades"]}),c=E({mutationFn:d=>A("POST",`/api/admin/secondary-market/trades/${d}/approve`),onSuccess:()=>{y("Trade approved. Participation transferred."),o()},onError:()=>y.error("Failed to approve trade")}),r=E({mutationFn:d=>A("POST",`/api/admin/secondary-market/trades/${d}/reject`),onSuccess:()=>{y("Trade rejected. Listing reopened."),o()},onError:()=>y.error("Failed to reject trade")}),l=(s==null?void 0:s.filter(d=>d.trade.status==="pending_admin"))??[],m=(s==null?void 0:s.filter(d=>d.trade.status!=="pending_admin"))??[];return n?e.jsx("div",{className:"flex justify-center py-20",children:e.jsx(Q,{className:"h-8 w-8 animate-spin text-muted-foreground"})}):e.jsxs("div",{className:"space-y-6",children:[e.jsxs(M,{children:[e.jsx(X,{children:e.jsxs(G,{className:"text-base flex items-center gap-2",children:["Pending Approval",l.length>0&&e.jsx(w,{className:"bg-amber-500 text-white rounded-full h-5 min-w-[1.25rem] flex items-center justify-center text-xs",children:l.length})]})}),e.jsx(B,{children:l.length===0?e.jsx("p",{className:"text-sm text-muted-foreground py-4 text-center",children:"No trades pending approval."}):e.jsx("div",{className:"space-y-3",children:l.map(({trade:d,listing:u,participation:x,loan:i})=>e.jsx("div",{className:"rounded-lg border bg-amber-50/30 p-4 space-y-3",children:e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs(w,{className:"bg-blue-100 text-blue-700",children:[(x==null?void 0:x.trancheLetter)??"?"," Tranche"]}),(i==null?void 0:i.loanNumber)&&e.jsxs("span",{className:"text-sm text-muted-foreground",children:["Loan ",i.loanNumber]})]}),e.jsxs("p",{className:"font-semibold",children:[we(d.amountUsd)," face value"]}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Seller asking ",ce(u.askingRateBps),", buyer agrees at ",ce(d.agreedRateBps),". LL fee: ",Se(d.amountUsd,d.feeBps)," (",d.feeBps,"bps)"]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Submitted ",new Date(d.createdAt).toLocaleDateString()]})]}),e.jsxs("div",{className:"flex gap-2 shrink-0",children:[e.jsxs(f,{size:"sm",variant:"outline",className:"gap-1.5 text-red-600 border-red-200 hover:bg-red-50",disabled:r.isPending,onClick:()=>r.mutate(d.id),children:[e.jsx(ws,{className:"h-4 w-4"}),"Reject"]}),e.jsxs(f,{size:"sm",className:"gap-1.5 bg-emerald-600 hover:bg-emerald-700",disabled:c.isPending,onClick:()=>c.mutate(d.id),children:[e.jsx(ne,{className:"h-4 w-4"}),"Approve"]})]})]})},d.id))})})]}),m.length>0&&e.jsxs(M,{children:[e.jsx(X,{children:e.jsx(G,{className:"text-base",children:"Trade History"})}),e.jsx(B,{children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b text-muted-foreground text-xs uppercase tracking-wide",children:[e.jsx("th",{className:"text-left pb-2",children:"Tranche"}),e.jsx("th",{className:"text-left pb-2",children:"Amount"}),e.jsx("th",{className:"text-left pb-2",children:"Rate"}),e.jsx("th",{className:"text-left pb-2",children:"LL Fee"}),e.jsx("th",{className:"text-left pb-2",children:"Status"}),e.jsx("th",{className:"text-left pb-2",children:"Date"})]})}),e.jsx("tbody",{className:"divide-y",children:m.map(({trade:d,participation:u})=>e.jsxs("tr",{children:[e.jsx("td",{className:"py-2",children:(u==null?void 0:u.trancheLetter)??"?"}),e.jsx("td",{className:"py-2 font-medium",children:we(d.amountUsd)}),e.jsx("td",{className:"py-2",children:ce(d.agreedRateBps)}),e.jsx("td",{className:"py-2",children:Se(d.amountUsd,d.feeBps)}),e.jsx("td",{className:"py-2",children:e.jsx(w,{className:Rs[d.status]??"",children:d.status})}),e.jsx("td",{className:"py-2 text-muted-foreground",children:d.approvedAt?new Date(d.approvedAt).toLocaleDateString():"-"})]},d.id))})]})})})]})]})}
11const Es=["all","active","pending_disbursement","payoff_pending_release","paid_off","defaulted","cancelled"],Ms=`${ss}/tx/`;function Z(s){return s?`${s.slice(0,8)}...${s.slice(-6)}`:""}function Bs(s){return s?`${s.slice(0,6)}...${s.slice(-4)}`:""}function U(s){return s==null?"—":`$${(typeof s=="string"?parseFloat(s):s).toLocaleString(void 0,{minimumFractionDigits:0,maximumFractionDigits:0})}`}function Os(s){return`${(s/100).toFixed(2)}%`}function de(s){if(!s)return"0.000000";try{const n=BigInt(s),o=BigInt("1000000000000000000"),c=n/o,l=(n%o).toString().padStart(18,"0").slice(0,6);return`${c.toLocaleString()}.${l}`}catch{return s}}function zs(s){switch(s){case"active":return e.jsx(w,{className:"bg-green-100 text-green-800 border-green-200",children:"Active"});case"paid_off":return e.jsx(w,{className:"bg-blue-100 text-blue-800 border-blue-200",children:"Paid Off"});case"pending_disbursement":return e.jsx(w,{className:"bg-amber-100 text-amber-800 border-amber-200",children:"Pending Disbursement"});case"payoff_pending_release":return e.jsx(w,{className:"bg-orange-100 text-orange-800 border-orange-200",children:"Payoff - Pending Release"});case"defaulted":return e.jsx(w,{className:"bg-red-100 text-red-800 border-red-200",children:"Defaulted"});case"cancelled":return e.jsx(w,{variant:"outline",className:"text-gray-500",children:"Cancelled"});default:return e.jsx(w,{variant:"outline",children:s})}}function Ce({hash:s}){return s?e.jsxs("a",{href:`${Ms}${s}`,target:"_blank",rel:"noopener noreferrer",className:"flex items-center gap-1 font-mono text-xs text-blue-600 hover:text-blue-800",children:[Z(s),e.jsx(Cs,{className:"h-3 w-3"})]}):e.jsx("span",{className:"text-gray-400",children:"—"})}function ke({displayName:s,walletAddress:n}){return e.jsx(ee,{children:e.jsxs(se,{children:[e.jsx(te,{asChild:!0,children:e.jsxs("div",{className:"flex items-center gap-1.5 cursor-default",children:[e.jsx(ks,{className:"h-3 w-3 text-gray-400 shrink-0"}),e.jsx("span",{className:"text-sm font-medium text-gray-800 truncate max-w-[120px]",children:s??Bs(n)??"—"})]})}),e.jsx(ae,{children:e.jsxs("div",{className:"space-y-0.5",children:[s&&e.jsx("p",{className:"font-medium",children:s}),e.jsx("p",{className:"font-mono text-xs text-gray-400",children:n??"no wallet"})]})})]})})}function _s({loan:s}){const n=s.landName??`Land #${s.landId}`,o=[s.landCounty,s.landState].filter(Boolean).join(", ");return e.jsx(ee,{children:e.jsxs(se,{children:[e.jsx(te,{asChild:!0,children:e.jsxs("div",{className:"flex items-start gap-1.5 cursor-default",children:[e.jsx(hs,{className:"h-3 w-3 text-gray-400 shrink-0 mt-0.5"}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-gray-800 truncate max-w-[150px]",children:n}),o&&e.jsx("p",{className:"text-xs text-gray-500",children:o})]})]})}),e.jsx(ae,{children:e.jsxs("div",{className:"space-y-0.5",children:[e.jsx("p",{className:"font-medium",children:n}),o&&e.jsx("p",{className:"text-xs text-gray-400",children:o}),e.jsxs("p",{className:"text-xs text-gray-400",children:["Land ID #",s.landId]})]})})]})})}function qs({loan:s,onSuccess:n}){const[o,c]=h.useState(!1),r=async()=>{c(!0);try{const m=await(await A("POST",`/api/admin/loans/${s.id}/relock-collateral`)).json();y("Collateral re-locked",{description:`${s.landName??"Loan"}: released old lock and re-locked ${U(s.principalUsd)} with correct precision. Tx: ${Z(m.lockTxHash)}`}),n()}catch(l){y.error("Re-lock failed",{description:l instanceof Error?l.message:"Unknown error"})}finally{c(!1)}};return e.jsx(ee,{children:e.jsxs(se,{children:[e.jsx(te,{asChild:!0,children:e.jsxs(f,{size:"sm",variant:"outline",className:"border-orange-300 text-orange-700 hover:bg-orange-50",onClick:r,disabled:o,children:[o?e.jsx($,{className:"h-3 w-3 animate-spin mr-1"}):e.jsx(Ps,{className:"h-3 w-3 mr-1"}),"Fix Lock"]})}),e.jsx(ae,{className:"max-w-xs",children:e.jsx("p",{children:"Re-locks this loan's SPV collateral with the correct 18-decimal wei precision."})})]})})}function Hs({loan:s,onSuccess:n}){const[o,c]=h.useState(!1),r=async()=>{c(!0);try{const m=await(await A("POST",`/api/admin/loans/${s.id}/release-pending-collateral`)).json();y("Collateral released",{description:`${s.landName??"Loan"}: ${U(s.principalUsd)} in SPV tokens returned to borrower. Tx: ${Z(m.txHash)}`}),n()}catch(l){y.error("Release failed",{description:l instanceof Error?l.message:"Unknown error"})}finally{c(!1)}};return e.jsx(ee,{children:e.jsxs(se,{children:[e.jsx(te,{asChild:!0,children:e.jsxs(f,{size:"sm",variant:"outline",className:"border-green-300 text-green-700 hover:bg-green-50",onClick:r,disabled:o,children:[o?e.jsx($,{className:"h-3 w-3 animate-spin mr-1"}):e.jsx(Ts,{className:"h-3 w-3 mr-1"}),"Release Collateral"]})}),e.jsx(ae,{className:"max-w-xs",children:e.jsx("p",{children:"Returns the borrower's SPV tokens from the vault (or treasury if vault is empty). Marks loan as paid off."})})]})})}function Vs({loan:s,onSuccess:n}){const[o,c]=h.useState(!1),[r,l]=h.useState(null),[m,d]=h.useState(!1),[u,x]=h.useState(!1),i=async()=>{c(!0),l(null),d(!0);try{const t=await fetch(`/api/admin/loans/${s.id}/default-preview`,{credentials:"include"});if(!t.ok)throw new Error(await t.text());l(await t.json())}catch(t){y.error("Could not load seizure preview",{description:t instanceof Error?t.message:"Failed to load preview"}),c(!1)}finally{d(!1)}},p=async()=>{x(!0);try{await A("POST",`/api/admin/loans/${s.id}/declare-default`);const t=U((r==null?void 0:r.vaultAmountUsd)??0),N=U((r==null?void 0:r.walletAmountUsd)??0);y("Loan defaulted. Tokens seized.",{description:`Vault: ${t} seized. Wallet: ${N} seized. All sent to treasury.`}),c(!1),n()}catch(t){y.error("Declare default failed",{description:t instanceof Error?t.message:"Unknown error"})}finally{x(!1)}},j=((r==null?void 0:r.vaultAmountUsd)??0)+((r==null?void 0:r.walletAmountUsd)??0);return e.jsxs(e.Fragment,{children:[e.jsxs(f,{size:"sm",variant:"outline",className:"border-red-300 text-red-700 hover:bg-red-50",onClick:i,children:[e.jsx(Ne,{className:"h-3 w-3 mr-1"}),"Declare Default"]}),e.jsx(Fe,{open:o,onOpenChange:c,children:e.jsxs(Ue,{className:"max-w-md",children:[e.jsxs($e,{children:[e.jsxs(Re,{className:"text-red-700 flex items-center gap-2",children:[e.jsx(Ne,{className:"h-5 w-5"}),"Declare Loan Default"]}),e.jsx(Ie,{asChild:!0,children:e.jsx("div",{className:"space-y-3 text-sm text-gray-700",children:m?e.jsxs("div",{className:"flex items-center gap-2 py-2",children:[e.jsx($,{className:"h-4 w-4 animate-spin text-gray-400"}),e.jsx("span",{children:"Loading on-chain balances..."})]}):r?e.jsxs(e.Fragment,{children:[e.jsxs("p",{children:["This will seize all SPV tokens for ",e.jsx("strong",{children:r.landName})," (Token ID ",r.tokenId,") from the borrower and send them to the Land Ledger treasury. This action cannot be undone."]}),e.jsxs("div",{className:"rounded-md border border-red-200 bg-red-50 p-3 space-y-2",children:[e.jsxs("div",{className:"flex justify-between items-start text-xs",children:[e.jsx("span",{className:"text-gray-600",children:"Vault (locked collateral)"}),e.jsxs("div",{className:"text-right",children:[e.jsx("div",{className:"font-semibold",children:U(r.vaultAmountUsd)}),e.jsxs("div",{className:"font-mono text-gray-500",children:[de(r.vaultAmountWei)," SPV"]})]})]}),e.jsxs("div",{className:"flex justify-between items-start text-xs",children:[e.jsx("span",{className:"text-gray-600",children:"Borrower wallet balance"}),e.jsxs("div",{className:"text-right",children:[e.jsx("div",{className:"font-semibold",children:U(r.walletAmountUsd)}),e.jsxs("div",{className:"font-mono text-gray-500",children:[de(r.walletAmountWei)," SPV"]})]})]}),e.jsxs("div",{className:"flex justify-between items-start text-xs border-t border-red-200 pt-1.5 mt-1",children:[e.jsx("span",{className:"font-medium text-red-800",children:"Total to seize"}),e.jsxs("div",{className:"text-right",children:[e.jsx("div",{className:"font-bold text-red-800",children:U(j)}),e.jsxs("div",{className:"font-mono text-red-700",children:[de((BigInt(r.vaultAmountWei||"0")+BigInt(r.walletAmountWei||"0")).toString())," SPV"]})]})]})]}),e.jsxs("p",{className:"text-xs text-gray-500",children:["Only tokens for Token ID ",r.tokenId," are seized. Any tokens the borrower holds for other properties are untouched."]})]}):null})})]}),e.jsxs(Ee,{children:[e.jsx(Me,{disabled:u,children:"Cancel"}),e.jsx(Be,{onClick:p,disabled:m||u||!r,className:"bg-red-600 hover:bg-red-700 text-white",children:u?e.jsxs(e.Fragment,{children:[e.jsx($,{className:"h-3 w-3 animate-spin mr-1"})," Seizing tokens..."]}):"Confirm Default and Seize Tokens"})]})]})})]})}function Ws(){const[s,n]=h.useState(""),[o,c]=h.useState(""),[r,l]=h.useState(""),[m,d]=h.useState(!1),[u,x]=h.useState(null),i=async()=>
11{if(!(!s||!o||!r)){d(!0),x(null);try{const j=await(await A("POST","/api/admin/recover-wallet-spv-tokens",{fromAddress:s,toAddress:o,tokenId:parseInt(r,10)})).json();x(j),y("Tokens recovered",{description:`Moved all SPV tokens for token ID ${r} from old wallet to new wallet. Tx: ${Z(j.txHash)}`})}catch(p){y.error("Recovery failed",{description:p instanceof Error?p.message:"Unknown error"})}finally{d(!1)}}};return e.jsxs(M,{className:"border-amber-200 bg-amber-50",children:[e.jsxs(X,{className:"pb-3",children:[e.jsxs(G,{className:"text-base flex items-center gap-2",children:[e.jsx(As,{className:"h-4 w-4 text-amber-600"}),"Recover Stranded SPV Tokens"]}),e.jsx(ue,{children:"Use this when a borrower changed wallets and their SPV tokens are stuck in the old address. Reads the full balance from the old wallet and moves all tokens to the new wallet using admin transfer."})]}),e.jsxs(B,{className:"space-y-3",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(S,{className:"text-xs",children:"Old wallet address (from)"}),e.jsx(T,{placeholder:"0x...",value:s,onChange:p=>n(p.target.value),className:"font-mono text-xs"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(S,{className:"text-xs",children:"New wallet address (to)"}),e.jsx(T,{placeholder:"0x...",value:o,onChange:p=>c(p.target.value),className:"font-mono text-xs"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(S,{className:"text-xs",children:"SPV Token ID (blockchainTokenId)"}),e.jsx(T,{placeholder:"e.g. 23",type:"number",value:r,onChange:p=>l(p.target.value),className:"text-xs"})]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(f,{size:"sm",onClick:i,disabled:m||!s||!o||!r,className:"bg-amber-600 hover:bg-amber-700 text-white",children:m?e.jsxs(e.Fragment,{children:[e.jsx($,{className:"h-3 w-3 mr-1.5 animate-spin"}),"Recovering..."]}):"Move Tokens"}),u&&e.jsxs("span",{className:"text-xs text-green-700 font-mono",children:["Done. Tx: ",Z(u.txHash)]})]})]})]})}function ha(){const[,s]=Ze(),o=new URLSearchParams(Ye()).get("tab"),c=o==="servicing"||o==="secondary"?o:"pipeline",[r,l]=h.useState("all"),[m,d]=h.useState(null),u=E({mutationFn:async t=>{const N=await A("DELETE",`/api/admin/loans/${t}`);if(!N.ok){const C=await N.json().catch(()=>({}));throw new Error(C.message??"Failed to delete loan")}},onSuccess:()=>{y("Loan deleted"),Te.invalidateQueries({queryKey:["/api/admin/loans"]}),p(),d(null)},onError:t=>y.error("Delete failed",{description:t.message})}),{data:x,isLoading:i,refetch:p}=Y({queryKey:["/api/admin/loans",r],queryFn:async()=>{const t=r==="all"?"/api/admin/loans":`/api/admin/loans?status=${r}`,N=await fetch(t,{credentials:"include"});if(!N.ok)throw new Error("Failed to fetch loans");return N.json()}}),j=(x==null?void 0:x.filter(t=>t.status==="active"))??[];return e.jsxs(es,{children:[e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900",children:"Loans"}),e.jsx("p",{className:"text-sm text-gray-500 mt-1",children:"Manage the loan pipeline, servicing payments, and secondary market trades."})]}),e.jsxs(f,{variant:"outline",size:"sm",onClick:()=>p(),children:[e.jsx($,{className:"h-4 w-4 mr-2"}),"Refresh"]})]}),e.jsxs(ds,{defaultValue:c,children:[e.jsxs(os,{children:[e.jsx(ie,{value:"pipeline",children:"Pipeline"}),e.jsx(ie,{value:"servicing",children:"Servicing"}),e.jsx(ie,{value:"secondary",children:"Secondary Market"})]}),e.jsxs(le,{value:"pipeline",className:"space-y-4 mt-4",children:[j.length>0&&r!=="paid_off"&&r!=="cancelled"&&e.jsxs(Oe,{className:"border-orange-200 bg-orange-50",children:[e.jsx(Ss,{className:"h-4 w-4 text-orange-600"}),e.jsx(ze,{className:"text-orange-800",children:'Active loans locked before the April 4, 2026 unit-precision fix may need collateral re-locking. Use the "Fix Lock" button on any affected active loan.'})]}),e.jsxs(ms,{children:[e.jsx(xs,{asChild:!0,children:e.jsxs(f,{variant:"ghost",size:"sm",className:"flex items-center gap-1.5 text-xs text-gray-500 hover:text-gray-700 px-0",children:[e.jsx(Qe,{className:"h-3.5 w-3.5"}),"Legacy Tools"]})}),e.jsx(us,{children:e.jsx("div",{className:"pt-2",children:e.jsx(Ws,{})})})]}),e.jsxs(M,{children:[e.jsxs(X,{className:"flex flex-row items-center justify-between pb-4",children:[e.jsxs("div",{children:[e.jsx(G,{children:"Loan Records"}),e.jsx(ue,{children:i?"Loading...":`${(x==null?void 0:x.length)??0} loan${(x==null?void 0:x.length)!==1?"s":""} found${j.length>0?` (${j.length} active)`:""}`})]}),e.jsxs(rs,{value:r,onValueChange:l,children:[e.jsx(ns,{className:"w-52",children:e.jsx(is,{placeholder:"Filter by status"})}),e.jsx(ls,{children:Es.map(t=>e.jsx(cs,{value:t,children:t==="all"?"All statuses":t.replace(/_/g," ").replace(/\b\w/g,N=>N.toUpperCase())},t))})]})]}),e.jsx(B,{className:"p-0",children:i?e.jsx("div",{className:"flex items-center justify-center h-32 text-gray-400",children:"Loading loans..."}):!x||x.length===0?e.jsx("div",{className:"flex items-center justify-center h-32 text-gray-400",children:"No loans foun
11d"}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs(Ae,{children:[e.jsx(Le,{children:e.jsxs(K,{className:"bg-gray-50",children:[e.jsx(b,{className:"w-12",children:"ID"}),e.jsx(b,{children:"Borrower"}),e.jsx(b,{children:"Lender"}),e.jsx(b,{children:"Land"}),e.jsx(b,{children:"Principal"}),e.jsx(b,{children:"Rate"}),e.jsx(b,{children:"Term"}),e.jsx(b,{children:"Status"}),e.jsx(b,{children:"Collateral Lock Tx"}),e.jsx(b,{children:"Disbursement Tx"}),e.jsx(b,{children:"Actions"})]})}),e.jsx(De,{children:x.flatMap((t,N)=>{const C=N===0||x[N-1].status!==t.status,L=t.status.replace(/_/g," ").replace(/\b\w/g,P=>P.toUpperCase()),k=x.filter(P=>P.status===t.status).length;return[...C?[e.jsx(K,{className:"bg-gray-100 border-t-2 border-gray-200",children:e.jsx(v,{colSpan:11,className:"py-1.5 px-4",children:e.jsxs("span",{className:"text-xs font-semibold uppercase tracking-wide text-gray-500",children:[L," (",k,")"]})})},`group-${t.status}`)]:[],e.jsxs(K,{className:`hover:bg-gray-50 ${t.status==="active"?"bg-green-50/30":""}`,children:[e.jsxs(v,{className:"font-mono text-sm font-medium",children:["#",t.id]}),e.jsx(v,{children:e.jsx(ke,{displayName:t.borrowerDisplayName,walletAddress:t.borrowerWalletAddress})}),e.jsx(v,{children:e.jsx(ke,{displayName:t.lenderDisplayName,walletAddress:t.lenderWalletAddress})}),e.jsx(v,{children:e.jsx(_s,{loan:t})}),e.jsx(v,{className:"font-semibold",children:U(t.principalUsd)}),e.jsx(v,{className:"text-sm",children:Os(t.rateBps)}),e.jsxs(v,{className:"text-sm",children:[t.termMonths,"mo"]}),e.jsx(v,{children:zs(t.status)}),e.jsx(v,{children:e.jsx(Ce,{hash:t.spvLockTxHash})}),e.jsx(v,{children:e.jsx(Ce,{hash:t.disbursementTxHash})}),e.jsx(v,{children:e.jsxs("div",{className:"flex items-center gap-1.5 flex-wrap",children:[e.jsx(f,{size:"sm",variant:"outline",className:"h-6 text-xs px-2",onClick:()=>s(`/admin/loans/v2/${t.id}`),children:"View"}),t.status==="active"&&e.jsxs(e.Fragment,{children:[e.jsx(qs,{loan:t,onSuccess:()=>p()}),e.jsx(Vs,{loan:t,onSuccess:()=>p()})]}),t.status==="payoff_pending_release"&&e.jsx(Hs,{loan:t,onSuccess:()=>p()}),t.status!=="active"&&e.jsx(ee,{children:e.jsxs(se,{children:[e.jsx(te,{asChild:!0,children:e.jsx(f,{size:"sm",variant:"ghost",className:"h-6 w-6 p-0 text-gray-400 hover:text-red-600 hover:bg-red-50",onClick:()=>d(t),children:e.jsx(ge,{className:"h-3 w-3"})})}),e.jsx(ae,{children:"Delete loan record"})]})})]})})]},t.id)]})})]})})})]})]}),e.jsx(le,{value:"servicing",className:"mt-4",children:e.jsx($s,{})}),e.jsx(le,{value:"secondary",className:"mt-4",children:e.jsx(Is,{})})]})]}),e.jsx(Fe,{open:!!m,onOpenChange:t=>{t||d(null)},children:e.jsxs(Ue,{children:[e.jsxs($e,{children:[e.jsxs(Re,{className:"flex items-center gap-2 text-red-700",children:[e.jsx(ge,{className:"h-5 w-5"}),"Delete Loan Record"]}),e.jsx(Ie,{asChild:!0,children:e.jsxs("div",{className:"space-y-2 text-sm text-gray-700",children:[e.jsxs("p",{children:["This will permanently delete loan ",e.jsxs("strong",{children:["#",m==null?void 0:m.id]})," and all associated payment records. This action cannot be undone."]}),m&&e.jsxs("div",{className:"rounded-md border border-gray-200 bg-gray-50 p-3 text-xs space-y-1",children:[e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-gray-500",children:"Principal"}),e.jsx("span",{className:"font-medium",children:U(m.principalUsd)})]}),e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-gray-500",children:"Status"}),e.jsx("span",{className:"font-medium",children:m.status.replace(/_/g," ")})]}),e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-gray-500",children:"Land"}),e.jsx("span",{className:"font-medium",children:m.landName??`Land #${m.landId}`})]})]})]})})]}),e.jsxs(Ee,{children:[e.jsx(Me,{disabled:u.isPending,children:"Cancel"}),e.jsx(Be,{onClick:()=>m&&u.mutate(m.id),disabled:u.isPending,className:"bg-red-600 hover:bg-red-700 text-white",children:u.isPending?e.jsxs(e.Fragment,{children:[e.jsx($,{className:"h-3 w-3 animate-spin mr-1"})," Deleting..."]}):"Delete Loan"})]})]})})]})}export{ha as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.