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 | 53x 86x 86x 86x 79x 7x 13x 7x 6x 11x 6x | import { Stack } from "@mui/material";
import GiveText from "@shared/Text/GiveText";
import { useGetFeatureFlagValues } from "FeatureFlags/useGetFeatureFlagValues";
import { TCustomFieldsSnapshot } from "@components/ManageMoney/TransactionTable/transactions.types";
import GiveCollapsableComponent from "@features/Merchants/MerchantSidePanel/GiveMerchantFile/businessOwners/GiveCollapsableComponent";
import TransactionSummaryDetails from "../Summary/TransactionSummaryDetails";
import { normalizeCustomFieldsSnapshot } from "@features/TransactionPanel/helpers/normalizeCustomFieldsSnapshot";
import { DEFAULT_CUSTOM_FIELDS_SECTION_TITLE } from "@sections/PayBuilder/Checkout/customFields.helpers";
type Props = {
data?: { customFieldsSnapshot?: TCustomFieldsSnapshot | null };
};
/**
* PAY-Builder016 — read-only custom-field answers on the transaction side panel
* (AC024-AC027). Shown under the Purchaser card only when the transaction
* captured at least one answered field.
*/
const TransactionCustomFields = ({ data }: Props) => {
const { isPayBuilderCustomFieldsEnabled } = useGetFeatureFlagValues();
// The snapshot ships in two shapes — see normalizeCustomFieldsSnapshot (GB-21600).
const { sectionTitle, answers } = normalizeCustomFieldsSnapshot(
data?.customFieldsSnapshot,
);
if (!isPayBuilderCustomFieldsEnabled || answers.length === 0) {
return null;
}
const ordered = [...answers].sort((a, b) => a.order - b.order);
const completed = ordered.filter((f) => (f.value ?? "").trim() !== "").length;
// AC027 — all fields optional and none answered: hide the whole section.
if (completed === 0) return null;
// The merchant's frozen Section Title, or the default when it captured none.
const title = sectionTitle.trim() || DEFAULT_CUSTOM_FIELDS_SECTION_TITLE;
const list = ordered.map((f) => ({
label: f.label,
// AC026 — optional empty fields render a dash.
value: (f.value ?? "").trim() || "-",
disableParseAmount: true,
}));
return (
<Stack spacing="21px" data-testid="transaction-custom-fields">
{/*
isFirst/isLast make this standalone accordion a self-contained card:
rounded 20px corners (radius.medium) matching the sibling summary cards
and no stray bottom border. The 20px inset on both the header and the
details keeps the left spacing aligned with the other panel sections.
*/}
<GiveCollapsableComponent
testId="transaction-custom-fields-accordion"
isFirst
isLast
sx={{ "& .MuiAccordionSummary-root": { px: "20px" } }}
title={
<GiveText variant="bodyM">
{`${title} (${completed}/${ordered.length})`}
</GiveText>
}
>
<TransactionSummaryDetails
list={list}
isHideBorder
sx={{ px: "20px" }}
/>
</GiveCollapsableComponent>
</Stack>
);
};
export default TransactionCustomFields;
|