jengacore.shadcn registry · Tailwind v4 · Radix and Base UI
Components
Product components · @jengacore/member-summary

MemberSummary

Msingi: identity, KYC and the three balances tellers ask for first.

Msingi
JM

Jeanne Mukamana

KYC verified
M-004211Kicukiro branch
Savings
1,250,000RWF
Shares
200,000RWF
Loan outstanding
374,999RWFIn arrears

Install

terminal
npx shadcn@latest add @jengacore/member-summary

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

Source

components/jc/member-summary.tsx
import * as React from "react"

import { Badge } from "@/components/ui/badge"
import { Amount } from "@/components/jc/amount"
import { IdChip } from "@/components/jc/id-chip"
import { cn } from "@/lib/utils"

export type Member = {
  name: string
  number: string
  branch: string
  initials: string
  kyc: "verified" | "pending" | "expired"
}

const KYC = {
  verified: { tone: "success", label: "KYC verified" },
  pending: { tone: "warning", label: "KYC pending" },
  expired: { tone: "danger", label: "KYC expired" },
} as const

/**
 * Msingi member header for SACCO and MFI staff: identity, KYC, and the three balances tellers ask for
 * first (savings, shares, loan outstanding). Balances carry no colour; states are badges.
 */
export function MemberSummary({
  member,
  currency,
  balances,
  arrears,
  actions,
  className,
}: {
  member: Member
  currency: string
  balances: { savings: string; shares: string; loan: string }
  /** Shows an "In arrears" badge next to the loan balance. */
  arrears?: boolean
  actions?: React.ReactNode
  className?: string
}) {
  const kyc = KYC[member.kyc]
  return (
    <section data-slot="member-summary" className={cn("grid gap-5 rounded-lg border border-border bg-card p-5 shadow-card contrast:border-input", className)}>
      <div className="flex flex-wrap items-center gap-4">
        <span className="grid size-12 place-items-center rounded-full bg-secondary text-base font-semibold text-secondary-foreground">{member.initials}</span>
        <div className="min-w-0 flex-1">
          <div className="flex flex-wrap items-center gap-2">
            <h2 className="text-lg leading-[26px] font-semibold">{member.name}</h2>
            <Badge tone={kyc.tone}>{kyc.label}</Badge>
          </div>
          <div className="mt-1 flex flex-wrap items-center gap-2 text-[13px] text-muted-foreground">
            <IdChip id={member.number} />
            <span>{member.branch}</span>
          </div>
        </div>
        {actions ? <div className="flex flex-wrap gap-2">{actions}</div> : null}
      </div>
      <dl className="grid grid-cols-1 gap-4 border-t border-border pt-4 sm:grid-cols-3">
        {(
          [
            ["Savings", balances.savings],
            ["Shares", balances.shares],
            ["Loan outstanding", balances.loan],
          ] as const
        ).map(([label, value]) => (
          <div key={label} className="grid gap-1">
            <dt className="eyebrow">{label}</dt>
            <dd className="flex items-center gap-2">
              <Amount value={value} currency={currency} size="lg" />
              {label === "Loan outstanding" && arrears ? <Badge tone="danger">In arrears</Badge> : null}
            </dd>
          </div>
        ))}
      </dl>
    </section>
  )
}