diff --git a/src/components/Button/Button.stories.js b/src/components/Button/Button.stories.js
index 0e6ead51..a44d5264 100644
--- a/src/components/Button/Button.stories.js
+++ b/src/components/Button/Button.stories.js
@@ -13,7 +13,7 @@ export const Supertask = Template.bind({});
export const SupertaskIcon = Template.bind({});
export const Primary = Template.bind({});
export const Secondary = Template.bind({});
-export const DangerDisabled = Template.bind({});
+export const Danger = Template.bind({});
export const Link = Template.bind({});
Supertask.args = {
@@ -47,12 +47,11 @@ Secondary.args = {
styling: "secondary",
};
-DangerDisabled.args = {
+Danger.args = {
id: "danger",
text: "Danger Button",
+ iconEnd: false,
styling: "danger",
- disabled: true,
- iconAltText: "disabled",
};
Link.args = {
diff --git a/src/components/Button/Button.test.js b/src/components/Button/Button.test.js
index 5d813146..95aa5961 100644
--- a/src/components/Button/Button.test.js
+++ b/src/components/Button/Button.test.js
@@ -6,13 +6,7 @@ import React from "react";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import { axe, toHaveNoViolations } from "jest-axe";
-import {
- Primary,
- Secondary,
- DangerDisabled,
- Link,
- Supertask,
-} from "./Button.stories";
+import { Primary, Secondary, Danger, Link, Supertask } from "./Button.stories";
expect.extend(toHaveNoViolations);
@@ -43,10 +37,8 @@ describe("Button", () => {
});
it("renders danger", () => {
- render();
- expect(screen.getByRole("button")).toHaveTextContent(
- DangerDisabled.args.text
- );
+ render();
+ expect(screen.getByRole("button")).toHaveTextContent(Danger.args.text);
expect(screen.getByRole("button")).toHaveClass("ds-btn-danger");
});
diff --git a/src/components/ContextualAlert/ContextualAlert.js b/src/components/ContextualAlert/ContextualAlert.js
index 9c38e04b..0d7a3349 100644
--- a/src/components/ContextualAlert/ContextualAlert.js
+++ b/src/components/ContextualAlert/ContextualAlert.js
@@ -50,19 +50,19 @@ export function ContextualAlert(props) {
>
{asHtml ? (
) : (
- {message_heading}
+ {message_heading}
)}
{asHtml ? (
) : (
- {message_body}
+ {message_body}
)}
diff --git a/src/components/FormErrorSummary/FormErrorSummary.js b/src/components/FormErrorSummary/FormErrorSummary.js
new file mode 100644
index 00000000..7d9cab4c
--- /dev/null
+++ b/src/components/FormErrorSummary/FormErrorSummary.js
@@ -0,0 +1,75 @@
+import PropTypes from "prop-types";
+import React from "react";
+import { ContextualAlert } from "../ContextualAlert/ContextualAlert";
+
+export function FormErrorSummary(props) {
+ const {
+ message_heading,
+ id,
+ alert_icon_id,
+ alert_icon_alt_text,
+ error_list,
+ whiteBG,
+ } = props;
+
+ return (
+
+ {error_list.map(({ line, id }, i) => (
+
+
+
+ {line}
+
+
+
+ ))}
+ ,
+ ]}
+ />
+ );
+}
+
+FormErrorSummary.propTypes = {
+ /**
+ * component id
+ */
+ id: PropTypes.string.isRequired,
+
+ /**
+ * id for the alert icon
+ */
+ alert_icon_id: PropTypes.string.isRequired,
+
+ /**
+ * Alternate text for the alert icon
+ */
+ alert_icon_alt_text: PropTypes.string.isRequired,
+
+ /**
+ * heading text
+ */
+ message_heading: PropTypes.string.isRequired,
+
+ /**
+ * An array of plaintext error messages and corresponding DOM ids for anchor links
+ */
+
+ error_list: PropTypes.arrayOf(
+ PropTypes.shape({
+ id: PropTypes.string,
+ line: PropTypes.string,
+ })
+ ).isRequired,
+ /**
+ * If true the background will be white, default is transparent.
+ */
+ whiteBG: PropTypes.bool,
+};
diff --git a/src/components/FormErrorSummary/FormErrorSummary.stories.js b/src/components/FormErrorSummary/FormErrorSummary.stories.js
new file mode 100644
index 00000000..35c0898c
--- /dev/null
+++ b/src/components/FormErrorSummary/FormErrorSummary.stories.js
@@ -0,0 +1,30 @@
+import { FormErrorSummary } from "./FormErrorSummary";
+export default {
+ title: "Components/FormErrorSummary",
+ component: FormErrorSummary,
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+
+Default.args = {
+ id: "formerrors",
+ error_list: [
+ { line: "Last name is required", id: "last_name" },
+ {
+ line: "Email address must be in the format of example@email.com",
+ id: "email",
+ },
+ { line: "Password must include both numbers and letters", id: "password" },
+ {
+ line: "A valid postal code is required for your selected city",
+ id: "postal_code",
+ },
+ ],
+ message_heading:
+ "The form could not be submitted because 4 errors were found",
+ alert_icon_alt_text: "danger icon",
+ alert_icon_id: "danger icon",
+ whiteBG: false,
+};
diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js
index e319942f..d0bb615d 100644
--- a/src/components/Header/Header.js
+++ b/src/components/Header/Header.js
@@ -26,6 +26,7 @@ export function Header(props) {
topnavProps,
useParentContainer,
customLink,
+ dataGcAnalyticsCustomClickInstitutionVariable,
} = props;
const containerClass = useParentContainer ? "" : "ds-container";
@@ -63,7 +64,7 @@ export function Header(props) {
locale={locale}
customLink={customLink}
dataGcAnalyticsCustomClickInstitutionVariable={
- props.dataGcAnalyticsCustomClickInstitutionVariable
+ dataGcAnalyticsCustomClickInstitutionVariable
}
/>
@@ -85,7 +86,7 @@ export function Header(props) {
customLink={customLink}
locale={locale}
dataGcAnalyticsCustomClickInstitutionVariable={
- props.dataGcAnalyticsCustomClickInstitutionVariable
+ dataGcAnalyticsCustomClickInstitutionVariable
}
/>
@@ -99,7 +100,7 @@ export function Header(props) {
customLink={customLink}
locale={locale}
dataGcAnalyticsCustomClickInstitutionVariable={
- props.dataGcAnalyticsCustomClickInstitutionVariable
+ dataGcAnalyticsCustomClickInstitutionVariable
}
/>
@@ -112,7 +113,7 @@ export function Header(props) {
menuList={menuProps.menuList}
onSignOut={menuProps.onSignOut}
dataGcAnalyticsCustomClickInstitutionVariable={
- props.dataGcAnalyticsCustomClickInstitutionVariable
+ dataGcAnalyticsCustomClickInstitutionVariable
}
/>
)}
@@ -253,6 +254,11 @@ Header.propTypes = {
})
),
+ /**
+ * Prefix for Adobe Analytics tag
+ */
+ dataGcAnalyticsCustomClickInstitutionVariable: PropTypes.string,
+
/**
* Test id for unit test
*/
diff --git a/src/components/Header/Header.stories.js b/src/components/Header/Header.stories.js
index c8c238a5..4b09dc5b 100644
--- a/src/components/Header/Header.stories.js
+++ b/src/components/Header/Header.stories.js
@@ -12,6 +12,7 @@ export const FrenchAuth = Template.bind({});
EnglishAuth.args = {
id: "header",
+ dataGcAnalyticsCustomClickInstitutionVariable: "Institution",
lang: "en",
menuProps: {
menuList: [
@@ -49,6 +50,7 @@ EnglishAuth.args = {
FrenchAuth.args = {
id: "header",
+ dataGcAnalyticsCustomClickInstitutionVariable: "Institution",
lang: "fr",
menuProps: {
menuList: [
diff --git a/src/components/Menu/Menu.js b/src/components/Menu/Menu.js
index 5b636e9d..d130f4f1 100644
--- a/src/components/Menu/Menu.js
+++ b/src/components/Menu/Menu.js
@@ -11,8 +11,16 @@ import FR from "../../translations/fr.json";
* Menu component
*/
export function Menu(props) {
- const { onClick, isAuthenticated, menuList, lang, onSignOut, demoBuffer } =
- props;
+ const {
+ onClick,
+ isAuthenticated,
+ menuList,
+ lang,
+ onSignOut,
+ demoBuffer,
+ dataGcAnalyticsCustomClickInstitutionVariable,
+ } = props;
+
const [showDropdown, setShowDropdown] = useState(false);
const dropdown = useRef(null);
@@ -53,11 +61,7 @@ export function Menu(props) {
onClick={() => setShowDropdown((e) => !e)}
data-gc-analytics-customclick={`${
props.dataGcAnalyticsCustomClickInstitutionVariable
- }:${
- showDropdown
- ? "Menu Contract-Diminuer Menu"
- : "Expand Menu-Etendre Menu"
- }`}
+ }:${showDropdown ? "Menu Contract" : "Expand Menu"}`}
aria-haspopup="true"
data-testid="menuButton"
aria-expanded={showDropdown}
@@ -119,7 +123,7 @@ export function Menu(props) {
index === 0 ? "ds-border-none" : "ds-border-t-2"
} ds-font-body ds-flex ds-items-center ds-h-[55px] ds-px-4 hover:ds-text-[#0535D2] focus:ds-outline-none ds-ring-offset-2 focus:ds-ring-2 ds-ring-[#0535D2] ds-rounded-sm focus:ds-border-none`}
onClick={element.showIcon ? onSignOut : onClick}
- data-gc-analytics-customclick={`${props.dataGcAnalyticsCustomClickInstitutionVariable}:Menu-${element.value}`}
+ data-gc-analytics-customclick={`${props.dataGcAnalyticsCustomClickInstitutionVariable}:Menu-${element.id}`}
>
{element.showIcon && (