diff --git a/src/components/contact-info-section/ContactInfoEmail.tsx b/src/components/contact-info-section/ContactInfoEmail.tsx
new file mode 100644
index 0000000000..fb47b4269f
--- /dev/null
+++ b/src/components/contact-info-section/ContactInfoEmail.tsx
@@ -0,0 +1,52 @@
+import * as React from "react";
+import { FC } from "react";
+import TextInput from "../atoms/input/TextInput";
+import { PatronSettingsV3, PatronV5 } from "../../core/fbs/model";
+import { useText } from "../../core/utils/text";
+import CheckBox from "../checkbox/Checkbox";
+import { ChangePatronProps } from "./types";
+
+export interface ContactInfoEmailProps {
+ className?: string;
+ patron: PatronV5 | PatronSettingsV3 | null;
+ changePatron: ChangePatronProps;
+ showCheckboxes: boolean;
+ isRequired?: boolean;
+}
+
+const ContactInfoEmail: FC = ({
+ className = "",
+ patron,
+ changePatron,
+ showCheckboxes,
+ isRequired = false
+}) => {
+ const t = useText();
+ return (
+ <>
+ changePatron(newEmail, "emailAddress")}
+ value={patron?.emailAddress}
+ label={t("patronContactEmailLabelText")}
+ />
+ {showCheckboxes && (
+
+ changePatron(newReceiveEmail, "receiveEmail")
+ }
+ id="email-messages"
+ selected={patron?.receiveEmail}
+ disabled={false}
+ label={t("patronContactEmailCheckboxText")}
+ />
+ )}
+ >
+ );
+};
+
+export default ContactInfoEmail;
diff --git a/src/components/contact-info-section/ContactInfoInputs.tsx b/src/components/contact-info-section/ContactInfoInputs.tsx
new file mode 100644
index 0000000000..acaeba3816
--- /dev/null
+++ b/src/components/contact-info-section/ContactInfoInputs.tsx
@@ -0,0 +1,48 @@
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { configure, render } from "@testing-library/react";
+import clsx from "clsx";
+import * as React from "react";
+import { FC } from "react";
+
+export interface ContactInfoInputsProps {
+ isInline: boolean;
+ children: React.ReactNode;
+ dataCy?: string;
+ className?: string;
+}
+
+// This component wraps the input fields for the contact info section
+// depending on the isInline prop.
+const ContactInfoInputs: FC = ({
+ isInline,
+ children,
+ dataCy = "contact-info-input",
+ className = undefined
+}) => {
+ if (!isInline) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ const renderableChildren = React.Children.toArray(children);
+ return (
+
+ {renderableChildren.map((child, i) => {
+ const childClassName = clsx("patron__input--desktop", {
+ "mr-16": i < renderableChildren.length - 1
+ });
+ return
{child}
;
+ })}
+
+ );
+};
+
+export default ContactInfoInputs;
diff --git a/src/components/contact-info-section/ContactInfoPhone.tsx b/src/components/contact-info-section/ContactInfoPhone.tsx
new file mode 100644
index 0000000000..6237e83138
--- /dev/null
+++ b/src/components/contact-info-section/ContactInfoPhone.tsx
@@ -0,0 +1,52 @@
+import * as React from "react";
+import { FC } from "react";
+import TextInput from "../atoms/input/TextInput";
+import { PatronSettingsV3, PatronV5 } from "../../core/fbs/model";
+import CheckBox from "../checkbox/Checkbox";
+import { useText } from "../../core/utils/text";
+import { ChangePatronProps } from "./types";
+
+export interface ContactInfoPhoneProps {
+ patron: PatronV5 | PatronSettingsV3 | null;
+ changePatron: ChangePatronProps;
+ showCheckboxes: boolean;
+ className?: string;
+}
+
+const ContactInfoPhone: FC = ({
+ patron,
+ changePatron,
+ showCheckboxes,
+ className = ""
+}) => {
+ const t = useText();
+ return (
+ <>
+
+ changePatron(newPhoneNumber, "phoneNumber")
+ }
+ value={patron?.phoneNumber}
+ label={t("patronContactPhoneLabelText")}
+ />
+ {showCheckboxes && (
+
+ changePatron(newReceiveSms, "receiveSms")
+ }
+ id="phone-messages"
+ selected={patron?.receiveSms}
+ disabled={false}
+ label={t("patronContactPhoneCheckboxText")}
+ />
+ )}
+ >
+ );
+};
+
+export default ContactInfoPhone;
diff --git a/src/components/contact-info-section/ContactInfoSection.tsx b/src/components/contact-info-section/ContactInfoSection.tsx
index 7565d697a8..335a0db24f 100644
--- a/src/components/contact-info-section/ContactInfoSection.tsx
+++ b/src/components/contact-info-section/ContactInfoSection.tsx
@@ -1,14 +1,12 @@
import React, { FC } from "react";
import clsx from "clsx";
import { PatronV5, PatronSettingsV3 } from "../../core/fbs/model";
-import TextInput from "../atoms/input/TextInput";
-import CheckBox from "../checkbox/Checkbox";
import { useText } from "../../core/utils/text";
import { useConfig } from "../../core/utils/config";
-
-export interface ChangePatronProps {
- (newValue: string | boolean, key: string): void;
-}
+import ContactInfoInputs from "./ContactInfoInputs";
+import ContactInfoPhone from "./ContactInfoPhone";
+import ContactInfoEmail from "./ContactInfoEmail";
+import { ChangePatronProps } from "./types";
interface ContactInfoSectionProps {
patron: PatronV5 | PatronSettingsV3 | null;
@@ -26,64 +24,9 @@ const ContactInfoSection: FC = ({
const t = useText();
const inputsClass = clsx("dpl-input", { input__desktop: inLine });
const config = useConfig();
- const textNotificationsEnabled =
+ const textNotificationsEnabledConfig =
config("textNotificationsEnabledConfig") === "1";
- const phoneNode = (
- <>
-
- changePatron(newPhoneNumber, "phoneNumber")
- }
- value={patron?.phoneNumber}
- label={t("patronContactPhoneLabelText")}
- />
- {showCheckboxes && textNotificationsEnabled && (
-
- changePatron(newReceiveSms, "receiveSms")
- }
- id="phone-messages"
- selected={patron?.receiveSms}
- disabled={false}
- label={t("patronContactPhoneCheckboxText")}
- />
- )}
- >
- );
- const emailNode = (
- <>
- changePatron(newEmail, "emailAddress")}
- value={patron?.emailAddress}
- label={t("patronContactEmailLabelText")}
- />
- {showCheckboxes && (
-
- changePatron(newReceiveEmail, "receiveEmail")
- }
- id="email-messages"
- selected={patron?.receiveEmail}
- disabled={false}
- label={t("patronContactEmailCheckboxText")}
- />
- )}
- >
- );
-
return (
@@ -94,17 +37,22 @@ const ContactInfoSection: FC = ({
{t("patronContactInfoBodyText")}
)}
- {inLine && (
-
-
{phoneNode}
-
{emailNode}
-
- )}
- {!inLine && (
- <>
- {phoneNode} {emailNode}
- >
- )}
+
+
+
+
);
};
diff --git a/src/components/contact-info-section/__snapshots__/ContactInfoInputs.tsx.snap b/src/components/contact-info-section/__snapshots__/ContactInfoInputs.tsx.snap
new file mode 100644
index 0000000000..c2591cf8f7
--- /dev/null
+++ b/src/components/contact-info-section/__snapshots__/ContactInfoInputs.tsx.snap
@@ -0,0 +1,36 @@
+// Vitest Snapshot v1
+
+exports[`ContactInfoInputs > Should NOT wrap the input fields if it is NOT inline 1`] = `
+
+
+ One input component
+
+
+ Another input component
+
+
+`;
+
+exports[`ContactInfoInputs > Should wrap the input fields if it is inline 1`] = `
+
+`;
diff --git a/src/components/contact-info-section/types.ts b/src/components/contact-info-section/types.ts
new file mode 100644
index 0000000000..ec855d2c17
--- /dev/null
+++ b/src/components/contact-info-section/types.ts
@@ -0,0 +1,3 @@
+export interface ChangePatronProps {
+ (newValue: string | boolean, key: string): void;
+}
diff --git a/src/tests/unit/__snapshots__/contact-info.test.tsx.snap b/src/tests/unit/__snapshots__/contact-info.test.tsx.snap
new file mode 100644
index 0000000000..c2591cf8f7
--- /dev/null
+++ b/src/tests/unit/__snapshots__/contact-info.test.tsx.snap
@@ -0,0 +1,36 @@
+// Vitest Snapshot v1
+
+exports[`ContactInfoInputs > Should NOT wrap the input fields if it is NOT inline 1`] = `
+
+
+ One input component
+
+
+ Another input component
+
+
+`;
+
+exports[`ContactInfoInputs > Should wrap the input fields if it is inline 1`] = `
+
+`;
diff --git a/src/tests/unit/contact-info.test.tsx b/src/tests/unit/contact-info.test.tsx
new file mode 100644
index 0000000000..f72b3cf513
--- /dev/null
+++ b/src/tests/unit/contact-info.test.tsx
@@ -0,0 +1,36 @@
+import { describe, expect, it } from "vitest";
+import React from "react";
+import { render } from "@testing-library/react";
+import { configure } from "@testing-library/dom";
+import ContactInfoInputs from "../../components/contact-info-section/ContactInfoInputs";
+
+configure({
+ testIdAttribute: "data-cy"
+});
+
+describe("ContactInfoInputs", () => {
+ it("Should wrap the input fields if it is inline", async () => {
+ const { getByTestId } = render(
+
+ One input component
+ Another input component
+
+ );
+
+ const contactInfoInputs = getByTestId("contact-info-input");
+
+ expect(contactInfoInputs).toMatchSnapshot();
+ });
+ it("Should NOT wrap the input fields if it is NOT inline", async () => {
+ const { getByTestId } = render(
+
+ One input component
+ Another input component
+
+ );
+
+ const contactInfoInputs = getByTestId("contact-info-input-inline");
+
+ expect(contactInfoInputs).toMatchSnapshot();
+ });
+});