All files / src/features/Settlements/ReconciliationHub/components HubCashPosition.tsx

100% Statements 9/9
50% Branches 6/12
100% Functions 5/5
100% Lines 9/9

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128                            2x             14x     14x                                                 2x 7x       7x 7x               7x                                 7x                                                                                              
import { Stack } from "@mui/material";
import GiveText from "@shared/Text/GiveText";
import { CoinsIcon } from "@phosphor-icons/react";
import { ReactNode } from "react";
import { useCustomThemeV2 } from "@theme/hooks/useCustomThemeV2";
import { ReconciliationHubView } from "../types";
import { formatHubAmount, formatHubAmountCompact } from "../format";
import SectionHeading from "./SectionHeading";
 
interface Props {
  data?: ReconciliationHubView;
}
 
/** A grey sub-panel on the right side of the cash-position card. */
const DistributionKey = ({
  label,
  value,
}: {
  label: string;
  value: ReactNode;
}) => (
  <Stack
    justifyContent="center"
    gap="4px"
    sx={(theme) => ({
      flex: "1 1 0",
      minWidth: 0,
      alignSelf: "stretch",
      padding: "24px 20px",
      borderRadius: "12px",
      overflow: "hidden",
      background: theme.palette.primitive?.transparent?.["darken-2"] ?? "rgba(0,0,0,0.02)",
    })}
  >
    <GiveText variant="bodyS" color="secondary" noWrap>
      {label}
    </GiveText>
    <GiveText variant="h3" noWrap>
      {value}
    </GiveText>
  </Stack>
);
 
/**
 * Cash Position: a single composite card. The left half shows the FBO
 * Available Balance with a coins badge; the right half holds two grey
 * distribution panels — Merchant Liabilities and the Buffer
 * (FBO Available − Merchant Liabilities) — all as-of period end.
 */
const HubCashPosition = ({ data }: Props) => {
  const { isLargeView } = useCustomThemeV2();
  // On smaller screens these FBO / liabilities / buffer figures reach the
  // billions and would ellipsize inside the fixed-width panels — compact them
  // to `M`/`B` (confirmed with design); keep full precision on large screens.
  const fmt = isLargeView ? formatHubAmount : formatHubAmountCompact;
  return (
    <Stack gap="12px" data-testid="hub-cash-position">
      <SectionHeading variant="h6">Cash Position</SectionHeading>
      <Stack
        direction="row"
        flexWrap="wrap"
        alignItems="flex-end"
        gap="12px"
        sx={(theme) => ({
          position: "relative",
          minHeight: { xs: "auto", md: "224px" },
          padding: "24px 20px",
          // On mobile the content stacks from the top, so reserve room for the
          // top-left coins badge; on desktop the tall card + bottom alignment
          // already clears it.
          paddingTop: { xs: "88px", md: "24px" },
          borderRadius: "8px",
          border: `1px solid ${theme.palette.border?.primary ?? "#E5E5E3"}`,
          background: theme.palette.surface?.primary ?? theme.palette.background?.paper,
        })}
      >
        {/* Coins badge, top-left */}
        <Stack
          alignItems="center"
          justifyContent="center"
          sx={(theme) => ({
            position: "absolute",
            top: "23px",
            left: "19px",
            padding: "13px",
            borderRadius: "50%",
            color: theme.palette.icon?.["icon-primary"] ?? theme.palette.text.primary,
            background: theme.palette.surface?.secondary ?? "#F5F5F3",
          })}
        >
          <CoinsIcon size={30} />
        </Stack>
 
        {/* Left: FBO Available Balance */}
        <Stack
          justifyContent="center"
          gap="4px"
          sx={{ flex: "1 1 280px", minWidth: "240px", minHeight: "97px" }}
        >
          <GiveText variant="bodyM" color="secondary">
            FBO Available Balance (USD)
          </GiveText>
          <GiveText variant="h2">{fmt(data?.fboAvailable)}</GiveText>
        </Stack>
 
        {/* Right: distribution panels */}
        <Stack
          direction="row"
          alignItems="stretch"
          gap="12px"
          sx={{ flex: "1 1 280px", minWidth: "240px", minHeight: "97px" }}
        >
          <DistributionKey
            label="Merchant Liabilities (USD)"
            value={fmt(data?.merchantLiabilities)}
          />
          <DistributionKey
            label="Buffer = FBO − Liabilities (USD)"
            value={fmt(data?.buffer)}
          />
        </Stack>
      </Stack>
    </Stack>
  );
};
 
export default HubCashPosition;