jengacore.shadcn registry · Tailwind v4 · Radix and Base UI
Components
Blocks · @jengacore/alert-queue

Alert queue

Mulisa home: KPI strip, compact queue sorted by SLA then score, alert detail in the side panel.

Mulisa
Monitor · today

Alert queue

Screened today1,284,330+4.1% vs last Monday
Open alerts41 over SLA
Blocked value38,920USD12 transfers
Median decision14MINTarget 30 min · met
RulesTransferAmountStatus
−00:12past SLA, breached92, high risk
Sanctions name matchALT-20931
SAN-001tx_01J9…H3V12,400.00USDBreached
00:18until SLA71, high risk
Velocity burstALT-20930
VEL-014tx_01J9…W7P480.00USDSLA < 1 h
00:41until SLA64, medium risk
Structuring below thresholdALT-20928
STR-003tx_01J9…N0D9,950.00USDIn review
01:52until SLA48, medium risk
New payee, high valueALT-20925
PAY-021tx_01J9…T5R3,200,000SLSHIn review

Install

terminal
npx shadcn@latest add @jengacore/alert-queue

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

Source

components/blocks/alert-queue.tsx
"use client"

import * as React from "react"
import { Download, Plus } from "lucide-react"

import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Sheet, SheetBody, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from "@/components/ui/sheet"
import { Amount } from "@/components/jc/amount"
import { PageHeader } from "@/components/jc/app-shell"
import { DataTable, type ColumnDef } from "@/components/jc/data-table"
import { IdChip } from "@/components/jc/id-chip"
import { KpiStrip } from "@/components/jc/kpi-strip"
import { RiskScore, type FiredRule } from "@/components/jc/risk-score"
import { RuleChip } from "@/components/jc/rule-chip"
import { ScoreChip } from "@/components/jc/score-chip"
import { SlaChip } from "@/components/jc/sla-chip"
import { StatusBadge } from "@/components/jc/status-badge"

export type QueueAlert = {
  id: string
  title: string
  transfer: string
  amount: string
  currency: string
  score: number
  slaMinutes: number
  status: string
  rules: FiredRule[]
  fresh?: boolean
}

const SAMPLE: QueueAlert[] = [
  { id: "ALT-20931", title: "Sanctions name match", transfer: "tx_01J9ZK4Q7MXH3V", amount: "12400", currency: "USD", score: 92, slaMinutes: -12, status: "breached", rules: [{ code: "SAN-001", condition: "Payee name matches a sanctions list entry ≥ 0.9" }], fresh: true },
  { id: "ALT-20930", title: "Velocity burst", transfer: "tx_01J9ZK4R2BQW7P", amount: "480", currency: "USD", score: 71, slaMinutes: 18, status: "sla_risk", rules: [{ code: "VEL-014", condition: "More than 12 transfers from one MSISDN in 10 min" }] },
  { id: "ALT-20928", title: "Structuring below threshold", transfer: "tx_01J9ZK3XQ1MN0D", amount: "9950", currency: "USD", score: 64, slaMinutes: 41, status: "in_review", rules: [{ code: "STR-003", condition: "Three transfers within 5% under the reporting threshold in 24 h" }] },
  { id: "ALT-20925", title: "New payee, high value", transfer: "tx_01J9ZK2M8DTT5R", amount: "3200000", currency: "SLSH", score: 48, slaMinutes: 112, status: "in_review", rules: [{ code: "PAY-021", condition: "First transfer to payee above 2,000,000 SLSH" }] },
]

const columns: ColumnDef<QueueAlert, unknown>[] = [
  { accessorKey: "slaMinutes", header: "SLA", cell: ({ row }) => <SlaChip minutes={row.original.slaMinutes} /> },
  { accessorKey: "score", header: "Score", cell: ({ row }) => <ScoreChip score={row.original.score} /> },
  {
    accessorKey: "title",
    header: "Alert",
    cell: ({ row }) => (
      <div className="grid">
        <span className="font-medium">{row.original.title}</span>
        <span className="font-mono text-xs text-muted-foreground">{row.original.id}</span>
      </div>
    ),
  },
  { id: "rules", header: "Rules", enableSorting: false, cell: ({ row }) => {
      const [rule] = row.original.rules
      return rule ? <RuleChip code={rule.code} /> : "—"
    } },
  { accessorKey: "transfer", header: "Transfer", enableSorting: false, cell: ({ row }) => <IdChip id={row.original.transfer} short /> },
  { accessorKey: "amount", header: "Amount", enableSorting: false, meta: { align: "right" }, cell: ({ row }) => <Amount value={row.original.amount} currency={row.original.currency} /> },
  { accessorKey: "status", header: "Status", enableSorting: false, cell: ({ row }) => <StatusBadge domain="alert" status={row.original.status} /> },
]

/** Mulisa triage: KPI row + compact queue sorted by SLA then score + the alert in a side panel. */
export function AlertQueue({ alerts = SAMPLE }: { alerts?: QueueAlert[] }) {
  const [selected, setSelected] = React.useState<QueueAlert | null>(null)
  const sorted = React.useMemo(() => [...alerts].sort((a, b) => a.slaMinutes - b.slaMinutes || b.score - a.score), [alerts])
  const breached = alerts.filter((a) => a.slaMinutes < 0).length

  return (
    <div className="flex flex-col gap-6">
      <PageHeader
        eyebrow="Monitor · today"
        title="Alert queue"
        actions={
          <>
            <Button variant="outline">
              <Download />
              Export
            </Button>
            <Button>
              <Plus />
              New rule
            </Button>
          </>
        }
      />
      <KpiStrip
        items={[
          { label: "Screened today", value: "1,284,330", note: <><b>+4.1%</b> vs last Monday</>, trend: "up" },
          { label: "Open alerts", value: String(alerts.length), note: <><b>{breached} over SLA</b></>, trend: "warn" },
          { label: "Blocked value", value: "38,920", unit: "USD", note: "12 transfers" },
          { label: "Median decision", value: "14", unit: "MIN", note: <><b>Target 30 min</b> · met</>, trend: "up" },
        ]}
      />
      <DataTable
        columns={columns}
        data={sorted}
        density="compact"
        getRowId={(r) => r.id}
        selectedId={selected?.id}
        isFresh={(r) => !!r.fresh}
        onRowClick={setSelected}
        empty={{ title: "No open alerts.", description: "New alerts appear here as transfers are screened." }}
      />
      <Sheet open={!!selected} onOpenChange={(o: boolean) => !o && setSelected(null)}>
        <SheetContent>
          {selected ? (
            <>
              <SheetHeader>
                <SheetDescription>{selected.id}</SheetDescription>
                <SheetTitle>{selected.title}</SheetTitle>
              </SheetHeader>
              <SheetBody className="flex flex-col gap-5">
                <div className="flex flex-wrap items-center gap-2">
                  <StatusBadge domain="alert" status={selected.status} />
                  <SlaChip minutes={selected.slaMinutes} />
                </div>
                <RiskScore score={selected.score} rules={selected.rules} />
                <dl className="grid grid-cols-[auto_1fr] gap-x-6 gap-y-2 text-[13.5px]">
                  <dt className="eyebrow leading-6">Transfer</dt>
                  <dd><IdChip id={selected.transfer} /></dd>
                  <dt className="eyebrow leading-6">Amount</dt>
                  <dd><Amount value={selected.amount} currency={selected.currency} /></dd>
                </dl>
              </SheetBody>
              <SheetFooter>
                <Button variant="outline" shortcut="C">Clear</Button>
                <Button variant="secondary" shortcut="E">Escalate</Button>
                <Button variant="destructive" shortcut="B">Block</Button>
              </SheetFooter>
            </>
          ) : null}
        </SheetContent>
      </Sheet>
    </div>
  )
}