All files / src/features/Merchants/MerchantSidePanel/components/PahReassignmentBanner PahReassignmentBanner.tsx

100% Statements 16/16
100% Branches 14/14
100% Functions 2/2
100% Lines 15/15

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                22x         22x         22x   22x 22x                     350x 350x 350x         350x                       350x   350x     350x                       350x   4x                                 1x              
import { useState } from "react";
import { Box } from "@mui/material";
import { InfoIcon, XIcon } from "@phosphor-icons/react";
import GiveAlert from "@shared/GiveAlert/GiveAlert";
import GiveIconButton from "@shared/IconButton/GiveIconButton";
import { checkPortals } from "@utils/routing";
import { useMerchantSidePanelContext } from "../../Provider/MerchantSidePanelProvider";
 
const ATTENTION_LABEL = "Attention";
 
// QA PAH006 (DEV): the new PAH had to re-onboard their identity. Once they
// finish, the acquirer is prompted to review the now-updated merchant details.
const PAH_CHANGED_REVIEW_DESCRIPTION =
  "The primary account holder for this merchant has been changed. Please review the updated information.";
 
// QA PAH006 (STG) / bug 4: the new PAH was already approved for another
// merchant, so no further approval is required — purely informational.
const PAH_PREVIOUSLY_APPROVED_DESCRIPTION =
  "The merchant's Primary Account Holder has been updated and was previously approved for another merchant; therefore, no additional approval is required.";
 
const REVIEW_BANNER_TEST_ID = "pah-changed-review-banner";
const PREVIOUSLY_APPROVED_BANNER_TEST_ID = "pah-previously-approved-banner";
 
/**
 * First-side-panel banner shown to the acquirer/provider when a merchant's
 * Primary Account Holder has been reassigned. Renders above the merchant title
 * (see SidePanelBody) per the PAH006 mockups. Two mutually-exclusive variants:
 *
 *  - identity-only re-onboarding finished  → "review the updated information"
 *  - new PAH already approved elsewhere     → "no additional approval is required"
 */
export default function PahReassignmentBanner() {
  const { data, isProvider } = useMerchantSidePanelContext();
  const { isAcquirerPortal, isEnterprisePortal } = checkPortals();
  const [isDismissed, setIsDismissed] = useState(false);
 
  // Merchants-first rollout: providers stay on the old owner-change flow, so the
  // new-flow banner only renders for acquirer/enterprise sessions on a merchant.
  const isEligible =
    !isProvider && (isAcquirerPortal || isEnterprisePortal);
 
  // Gate the "review the updated information" banner on an ACTUAL reassignment
  // the new PAH has engaged with — it appears once they have accepted and
  // submitted identity (state === "ready_for_approval"), which is when there is
  // genuinely updated info for the acquirer to review. Do NOT gate on the raw
  // `isPahReassignmentIdentityOnly` flag: the BE derives it merchant-wide from
  // "onboarding completed && open PAH-identity task" with no reassignment
  // awareness, so it is true for any merchant sitting in underwriting/KYB — even
  // one whose PAH was never changed (`pendingChangeRequest` null). That caused
  // the banner to show on merchants with no reassignment (PAH006 regression).
  const isIdentityOnlyReview =
    data?.pahReassignment?.state === "ready_for_approval";
  const isPreviouslyApproved =
    data?.pahReassignment?.state === "pending_reassignment" &&
    data?.pahReassignment?.newPahStatusName === "approved";
 
  const banner = isIdentityOnlyReview
    ? {
        description: PAH_CHANGED_REVIEW_DESCRIPTION,
        testId: REVIEW_BANNER_TEST_ID,
      }
    : isPreviouslyApproved
    ? {
        description: PAH_PREVIOUSLY_APPROVED_DESCRIPTION,
        testId: PREVIOUSLY_APPROVED_BANNER_TEST_ID,
      }
    : null;
 
  if (!isEligible || isDismissed || !banner) return null;
 
  return (
    <Box sx={{ position: "relative" }}>
      {/* Neutral (gray) styling with an info icon, per the PAH006 mockups. */}
      <GiveAlert
        type="default"
        variant="alert"
        withBorder
        Icon={<InfoIcon />}
        label={ATTENTION_LABEL}
        description={banner.description}
        dataTestId={banner.testId}
        textContainerSx={{ paddingRight: "28px" }}
      />
      <GiveIconButton
        Icon={XIcon}
        variant="ghost"
        size="small"
        onClick={() => setIsDismissed(true)}
        data-testid={`${banner.testId}-close`}
        sx={{ position: "absolute", top: 8, right: 8 }}
      />
    </Box>
  );
}