Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RENO-3681: NewsletterSignup Component #1422

Merged
merged 43 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
cde951b
NewsletterSignup as Refactored FeedbackBox
aarnold101 Sep 8, 2023
6e6b373
NewsletterSignup as exposed Form
aarnold101 Sep 8, 2023
d7427a7
React EmailSubscription as DS Component
aarnold101 Sep 8, 2023
8710deb
NewsLetterSignup add getSectionColors function, and other advances
aarnold101 Sep 14, 2023
0b2b4a9
Merge branch 'development' into RENO-3681/newslettersignup-component
aarnold101 Sep 14, 2023
735e4c7
NewsletterSignup Functional Layout
aarnold101 Sep 20, 2023
00f217b
NewsletterSignup w/o onSubmit funtionality
aarnold101 Sep 22, 2023
706bf00
NewsletterSignup Near Complete Functionality
aarnold101 Sep 22, 2023
e7952c1
NewsletterSignup Updates & Fixes
aarnold101 Sep 25, 2023
5983419
NewsletterSignup Tests Round 1
aarnold101 Sep 26, 2023
3bd8d9d
NewsletterSignup w/o 3-second Timer
aarnold101 Sep 26, 2023
ac17c39
code cleanup
nypl-wluisi Sep 26, 2023
747b451
more code cleanup
nypl-wluisi Sep 27, 2023
4b33145
NewsletterSignup Update w/ Testing
aarnold101 Sep 28, 2023
8d53b28
Merge branch 'development' into RENO-3681/newslettersignup-component
aarnold101 Sep 28, 2023
f9dc57d
NewsletterSignup Snapshot Update
aarnold101 Sep 28, 2023
bcbb3b4
NewsletterSignup Minor Updates
aarnold101 Sep 28, 2023
117de84
NewsletterSignup Snapshot Update
aarnold101 Sep 28, 2023
8c603a9
code/storybook clean up
isastettler Oct 4, 2023
39670cc
fix darkmode, update storybook
isastettler Oct 4, 2023
e10e3de
add onChange and onSubmit test
isastettler Oct 5, 2023
26be513
fix onSubmit test, fix dark mode border bug
isastettler Oct 5, 2023
f7532ca
update confirmation props, update storybook, tests and Snapshots acco…
isastettler Oct 5, 2023
fa0c034
update storybook, add privacyPolicyLink prop
isastettler Oct 6, 2023
11aafed
fix title storybook bug, updated styles
isastettler Oct 6, 2023
87cc43d
fix descriptionText bug
isastettler Oct 10, 2023
7d141cc
fix "blogs" border color, add test for html props passed
isastettler Oct 10, 2023
f6bdbe9
add NewsletterSignup to component export file
isastettler Oct 10, 2023
abbe6eb
Add working onSubmit function and update .mdx
aarnold101 Oct 10, 2023
a4460e1
Merge branch 'development' into RENO-3681/newslettersignup-component
aarnold101 Oct 10, 2023
2b15b97
add props for error message, update styling and tests, add Newsletter…
isastettler Oct 11, 2023
9b31ea7
update storybook stories, fix typo
isastettler Oct 11, 2023
650e487
add interavtive example to storybook
isastettler Oct 11, 2023
cfcab79
add actions for onChange and onSubmit
isastettler Oct 11, 2023
8e5430f
remove styling, fix typos
isastettler Oct 12, 2023
d34bcc7
update as per PR comments
isastettler Oct 12, 2023
d926063
update snapshots
isastettler Oct 12, 2023
d99e940
Merge branch 'development' into RENO-3681/newslettersignup-component
isastettler Oct 12, 2023
1e634b1
update props, comments as discussed, update test and doc accordingly
isastettler Oct 12, 2023
3a56d1f
update breakpoints, remove reduntant content
isastettler Oct 12, 2023
917feb0
update breakpoint - the one that got away
isastettler Oct 12, 2023
3f42b6a
change html tags to ds components
isastettler Oct 12, 2023
77c31d7
update Text styles, fix typo for privacyPolicyLink, update tests
isastettler Oct 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ lib
dist
.vscode
.eslintcache
coverage
coverage
.idea
126 changes: 126 additions & 0 deletions src/components/NewsletterSignup/NewsletterSignup.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { ArgTypes, Canvas, Description, Meta, Source } from "@storybook/blocks";

import * as NewsletterSignupStories from "./NewsletterSignup.stories";
import Link from "../Link/Link";

<Meta of={NewsletterSignupStories} />

# NewsletterSignup

| Component Version | DS Version |
| ----------------- | ------------ |
| Added | `Prerelease` |
| Latest | `Prerelease` |

## Table of Contents

- {<Link href="#overview" target="_self">Overview</Link>}
- {<Link href="#component-props" target="_self">Component Props</Link>}
- {<Link href="#accessibility" target="_self">Accessibility</Link>}

## Overview

<Description of={NewsletterSignupStories} />


**Note**: The `NewsletterSignup` example
below alternately renders the "confirmation" and "error" screens on each form
submission. This is just to demonstrate the different states of the component.
isastettler marked this conversation as resolved.
Show resolved Hide resolved
In practice, the consuming app is responsible for handling the form submission.

## Component Props

<Canvas of={NewsletterSignupStories.WithControls} />

<ArgTypes of={NewsletterSignupStories.WithControls} />

<Source
code=' const sampleOnSubmitValue = async (e: any) => {
e.preventDefault();

//Create dynamic Google Analytics values
const gaEventCategory = "Email Subscription Forms";
// const gaEventActionName = `Subscribe - ${asPath}`; // example: Subscribe - /research
const gaEventActionName = `Subscribe - Testing`; // example: Subscribe - /research
const gaEventLabel = `Success ${salesforceSourceCode}`; // example: Success research

setIsSubmitting(true);

const endpoint = "/api/salesforce";

// Form the request for sending data to the server.
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: e.target.email.value,
listID: salesforceListId,
sourceCode: salesforceSourceCode,
}),


// Send the form and await response.
try {
const response = await fetch(endpoint, options);
const result = await response.json();

window.gtag("event", gaEventActionName, {
eventCategory: gaEventCategory,
eventLabel: gaEventLabel,
});

setStatus(result.statusCode);
setIsSubmitted(true);
} catch (error) {
setStatus("ERROR");
setIsSubmitted(true);
}
setIsSubmitting(false);
}
};' />

## Accessibility

The `NewsletterSignup` component is a complex component built from various Reservoir
DS and Chakra components. The two main components are the DS `Button` component
isastettler marked this conversation as resolved.
Show resolved Hide resolved
used to open Chakra's `Drawer` component.

When the primary button is clicked, the dialog opens and focus is set to the
isastettler marked this conversation as resolved.
Show resolved Hide resolved
first focusable element which is the "close" button that contains minus icon in
the header of the dialog. While opened, focus is trapped within the dialog until
it is closed either by clicking on the "close" or "Cancel" buttons, pressing the
"Escape" key, or by clicking outside of the dialog. When the `NewsletterSignup`
component is closed, focus is set back to the primary button that opened the
dialog.
aarnold101 marked this conversation as resolved.
Show resolved Hide resolved

The markup of the `NewsletterSignup` structurally matches the modal dialog pattern
isastettler marked this conversation as resolved.
Show resolved Hide resolved
that is implemented by Chakra's `Modal` and `Drawer` components. The container
has `role=”dialog”`, `aria-modal=”true”`, `tabindex={0}`, `aria-labelledby` that
references the title within the dialog, and `aria-describedby` that references a
descriptive piece of text within the dialog.
isastettler marked this conversation as resolved.
Show resolved Hide resolved

Within the `NewsletterSignup` component, the radio input field is created from the DS
aarnold101 marked this conversation as resolved.
Show resolved Hide resolved
`RadioGroup` and `Radio` components, and input fields are created from the DS
`TextInput` component. Each of these components has their own accessibility
features documented in their respective Storybook pages.

When the form is submitted, focus is set to the confirmation message or the
error message if an error occurs.

Whereas the `NewsletterSignup`'s primary button element is placed within the DOM
structure where it is rendered, the dialog DOM structure is appended to the end
of the DOM tree and it is done by Chakra.
aarnold101 marked this conversation as resolved.
Show resolved Hide resolved
isastettler marked this conversation as resolved.
Show resolved Hide resolved

Resources:

- [MDN ARIA: dialog role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/dialog_role)
isastettler marked this conversation as resolved.
Show resolved Hide resolved
- [W3C ARIA role=dialog](https://www.w3.org/WAI/GL/wiki/Using_ARIA_role%3Ddialog_to_implement_a_modal_dialog_box)
- [Chakra Modal Accessibility](https://v1.chakra-ui.com/docs/components/overlay/modal#accessibility)
- [Chakra Drawer Accessibility](https://v1.chakra-ui.com/docs/components/overlay/drawer#accessibility)
- [DS Button Accessibility](../?path=/docs/components-form-elements-button--docs#accessibility)
- [DS TextInput Accessibility](../?path=/docs/components-form-elements-textinput--docs#accessibility)
- [DS Radio Accessibility](../?path=/docs/components-form-elements-radio--docs#accessibility)
- [DS RadioGroup Accessibility](../?path=/docs/components-form-elements-radiogroup--docs#accessibility)

141 changes: 141 additions & 0 deletions src/components/NewsletterSignup/NewsletterSignup.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import type { Meta, StoryObj } from "@storybook/react";
import { withDesign } from "storybook-addon-designs";
import useStateWithDependencies from "../../hooks/useStateWithDependencies";
import NewsletterSignup from "./NewsletterSignup";

const meta: Meta<typeof NewsletterSignup> = {
title: "Components/Form Elements/NewsletterSignup",
component: NewsletterSignup,
decorators: [withDesign],
parameters: {
jest: ["NewsletterSignup.test.tsx"],
},
argTypes: {
bigfishdesign13 marked this conversation as resolved.
Show resolved Hide resolved
className: { control: false },
id: { control: false },
confirmationText: {
control: "text",
table: {
defaultValue: {
summary:
"Thank you! You have successfully subscribed to our email updates! You can update your email subscription preferences at any time using the links at the bottom of the email.",
},
},
},
descriptionText: {
control: "text",
table: {
defaultValue: {
summary:
"Stay connected with the latest research news from NYPL, including information about our events, programs, exhibitions, and collections.",
},
isastettler marked this conversation as resolved.
Show resolved Hide resolved
},
},
formHelperText: {
control: "text",
},
newsletterSignupType: {
control: "select",
table: {
defaultValue: {
summary: "whatsOn",
},
},
},
view: {
control: "select",
table: {
defaultValue: {
summary: "form",
},
},
},
title: {
control: "text",
table: { defaultValue: { summary: "Sign Up for Our Newsletter!" } },
},
},
};

export default meta;
type Story = StoryObj<typeof NewsletterSignup>;

const NewsletterSignupWithControls = (args) => {
const [view, setView] = useStateWithDependencies(args.view);
const [isInvalidEmail, setIsInvalidEmail] = useStateWithDependencies(
args.isInvalidEmail
);
const [confirmationText, setConfirmationText] = useStateWithDependencies(
args.confirmationText
);
const onSubmit = (values?: { [key: string]: string }) => {
let timer = setTimeout(() => {
setView("confirmation");
setConfirmationText(
"This is going to change your life. Check out those values in the console!"
);
}, 3000);
switch (values.email) {
case "":
setIsInvalidEmail(true);
clearTimeout(timer);
break;
case "[email protected]":
setView("error");
clearTimeout(timer);
break;
}
console.log(
"Submitted values:",
values,
"isInvalidEmail: ",
isInvalidEmail,
"View: ",
view
);
};
return (
<NewsletterSignup
{...args} // @todo All the same values below are already contained in this ...args array. But the ones below get to "win." I dunno why. Cuz they come after?
aarnold101 marked this conversation as resolved.
Show resolved Hide resolved
onSubmit={onSubmit}
view={view}
isInvalidEmail={isInvalidEmail}
confirmationText={confirmationText}
/>
);
};

// Example hidden field values.
const hiddenFields = {
"hidden-field-1": "hidden-field-value-1",
"hidden-field-2": "hidden-field-value-2",
};

/**
* Main Story for the NewsletterSignup component. This must contains the `args`
* and `parameters` properties in this object.
*/
export const WithControls: Story = {
args: {
className: undefined,
confirmationText:
"Fantastic! You're all set. Check the console for the data you submitted.",
aarnold101 marked this conversation as resolved.
Show resolved Hide resolved
descriptionText: "This is it.",
formHelperText: "You can do this.",
hiddenFields: { hiddenFields },
id: undefined,
isInvalidEmail: false,
newsletterSignupType: "whatsOn",
onSubmit: undefined,
title: "The Newsletter Everyone Is Talking About",
view: "form",
},
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/file/qShodlfNCJHb8n03IFyApM/Main?node-id=80849%3A174194&mode=dev",
},
jest: "NewsletterSignup.test.tsx",
},
render: (args) => <NewsletterSignupWithControls {...args} />,
};
Loading