jengacore.shadcn registry · Tailwind v4 · Radix and Base UI
Components
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
Healthy
Net position
42,500.50USD
28%

Net debit cap 150,000.00 USD; alert at 80%.

horncb · USD
Horn Commercial Bank
Near cap
Net position
215,000.00USD
86%

Net debit cap 250,000.00 USD; alert at 80%.

horncb · SLSH
Horn Commercial Bank
Net credit
Net position
−1,200,000SLSH
0%

Net debit cap 90,000,000 SLSH; alert at 80%.

Install

terminal
npx shadcn@latest add @jengacore/settlement-position

Without the namespace configured: npx shadcn@latest add https://ui.jengacore.com/r/<new-york-v4|base-nova>/settlement-position.json

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>
  )
}