Product components · @jengacore/settlement-position
SettlementPosition
Finance Portal: net position against the net debit cap, per participant and currency.
Finance Portal
sahanmm · USD
Sahan Mobile Money
Net position
42,500.50USD28%
Net debit cap 150,000.00 USD; alert at 80%.
horncb · USD
Horn Commercial Bank
Net position
215,000.00USD86%
Net debit cap 250,000.00 USD; alert at 80%.
horncb · SLSH
Horn Commercial Bank
Net position
−1,200,000SLSH0%
Net debit cap 90,000,000 SLSH; alert at 80%.
Install
terminal
npx shadcn@latest add @jengacore/settlement-positionWithout the namespace configured: npx shadcn@latest add https://ui.jengacore.com/r/<new-york-v4|base-nova>/settlement-position.json
Registry dependencies
Source
components/jc/settlement-position.tsx
import * as React from "react"
import { Badge } from "@/components/ui/badge"
import { Amount } from "@/components/jc/amount"
import { Meter } from "@/components/jc/meter"
import { formatAmount } from "@/lib/jengacore/format"
import { cn } from "@/lib/utils"
/**
* Finance Portal card per participant AND currency: the Mojaloop net position against the net debit cap.
* Meter green below the alert threshold, amber from it, red from 95%. The cap is stated in words.
* One card per currency: never sum USD and the local currency.
*/
export function SettlementPosition({
participant,
fspId,
currency,
position,
netDebitCap,
threshold = 80,
className,
}: {
participant: string
fspId: string
currency: string
/** Net position as a decimal string. Positive = net debit (owes), negative = net credit. */
position: string
netDebitCap: string
threshold?: number
className?: string
}) {
const pos = Number(position)
const cap = Number(netDebitCap)
const used = cap > 0 && pos > 0 ? (pos / cap) * 100 : 0
const state =
pos <= 0
? { tone: "info" as const, label: "Net credit" }
: used >= 95
? { tone: "danger" as const, label: "At cap" }
: used >= threshold
? { tone: "warning" as const, label: "Near cap" }
: { tone: "success" as const, label: "Healthy" }
return (
<section data-slot="settlement-position" className={cn("grid min-w-0 grid-cols-1 gap-3 rounded-lg border border-border bg-card p-5 shadow-card contrast:border-input", className)}>
<div className="flex flex-wrap items-start justify-between gap-x-3 gap-y-1.5">
<div className="min-w-0">
<div className="eyebrow">
{fspId} · {currency}
</div>
<div className="mt-0.5 text-[15px] font-semibold">{participant}</div>
</div>
<Badge tone={state.tone}>{state.label}</Badge>
</div>
<div>
<div className="text-xs text-muted-foreground">Net position</div>
<Amount value={position} currency={currency} size="lg" />
</div>
<Meter percent={used} threshold={threshold} label={`Net debit cap used, ${participant}, ${currency}`} showValue />
<p className="text-[13px] text-muted-foreground">
Net debit cap {formatAmount(netDebitCap, currency)} {currency}; alert at {threshold}%.
</p>
</section>
)
}