Skip to content

Conversation

@Marianaguardian
Copy link
Contributor

What does this change?

Investigate hiding the sign up component

Why?

There is an ambition to hide the sign up component that appears in articles when a user has already signed up to the newsletter in question. This would be a nice "quality of life" update that should make the sign up embeds less intrusive.

Ticket link: #14889

Subtask ticket link : #14890

Screenshots

Before After
before after

@Marianaguardian Marianaguardian linked an issue Nov 26, 2025 that may be closed by this pull request
7 tasks
@github-actions
Copy link

Hello 👋! When you're ready to run Chromatic, please apply the run_chromatic label to this PR.

You will need to reapply the label each time you want to run Chromatic.

Click here to see the Chromatic project.

@github-actions
Copy link

github-actions bot commented Nov 26, 2025

@github-actions
Copy link

github-actions bot commented Nov 26, 2025

}: EmailSignUpWrapperProps) => {
const [idApiUrl] = useState(() => {
if (typeof window === 'undefined') return '';
return window.guardian?.config?.page?.idApiUrl ?? '';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might it be better to return undefined rather than an empty string here and then make the type string | undefined?

@Marianaguardian Marianaguardian requested a review from a team as a code owner November 28, 2025 14:43
Comment on lines 41 to 43
if (isSubscribed === true) {
return null;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean we initially render the the newsletter component and then remove it if we determine there is a subscription?

I assume we have considered this approach will cause the least layout shift vs not showing and then inserting.

There is also the possibility of showing a newsletter related placeholder and replacing with the aim of zero layout shift.


setIsSubscribed(isUserSubscribed);
} catch (error) {
console.error('Error fetching newsletters:', error);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than console.error, we have a Sentry reportError function on the window which will allow you to report errors to Sentry. Here's an example e.g.:

window.guardian.modules.sentry.reportError(
new Error(errorMessage),
'rr-banner',
);

Copy link
Member

@arelra arelra Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have said earlier, any access of window should be inside a useEffect because:

a) that is the right place for side-effects h/t @JamieB-gu
b) so there is no risk of the component being used in a server render and causing an exception in the main render path

@Marianaguardian
Copy link
Contributor Author

Looks great, was just wondering if it was simpler to mock the useAuthStatus hook rather than everything that it uses on the window?

Good question! I tried mocking useAuthStatus directly, but Storybook doesn’t support jest.mock() since it runs in a real browser. The hook reads the actual auth state from the browser, so we can’t override it that way.

Using Webpack’s resolve.alias is the recommended approach — it lets us cleanly swap the identity module and control the auth state per story.

Copy link
Contributor

@JamieB-gu JamieB-gu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! 👍 for the tests and JSDocs.

A few questions and comments, one related to @georgerichmond 's point above.

}
}

const mockAccessToken = {
Copy link
Contributor

@JamieB-gu JamieB-gu Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Note, this is a reply to George's comment above, but the GH review UI might not show this clearly).

Doesn't the useAuthStatus hook also return this data via the SignedIn type though? I can also see that the SecureSignup component relies on a few different functions/hooks to retrieve information about the signed in status and email address, such as lazyFetchEmailWithTimeout and useIsSignedIn, which in turn rely on this?

An alternative might be to use storybook's built-in mocking1 for the modules in question? Given that you've already got tests for useNewsletterSubscription we probably don't need to re-test the underlying implementation in storybook, as we just want to test the resulting component behaviour. Therefore we could add the following to storybook's preview.ts to set up mocking for the relevant modules:

sb.mock(import('../src/lib/useNewsletterSubscription.ts'), { spy: true });
sb.mock(import('../src/lib/fetchEmail.ts'), { spy: true });
sb.mock(import('../src/lib/useAuthStatus.ts'), { spy: true });

Then we can use beforeEach in storybook2 to mock the specific functionality we care about. So, for each story:

LoadingState:

    async beforeEach() {
		mocked(useNewsletterSubscription).mockReturnValue(undefined);
	},

DefaultStory/DefaultStoryWithPrivacy:

    async beforeEach() {
		mocked(useNewsletterSubscription).mockReturnValue(false);
	},

SignedInNotSubscribed:

    async beforeEach() {
		mocked(useNewsletterSubscription).mockReturnValue(false);
		mocked(lazyFetchEmailWithTimeout).mockReturnValue(() => Promise.resolve("mock email"));
		mocked(useIsSignedIn).mockReturnValue(true);
	},

SignedInAlreadySubscribed:

    async beforeEach() {
		mocked(useNewsletterSubscription).mockReturnValue(true);
	},

I think this would allow you to avoid writing custom mocks for the identity module, and the auth decorators too. However, I doubt we have other examples of this in the codebase, as I believe it's a relatively recent feature (Storybook 9), so I'd be happy to discuss if helpful.

Footnotes

  1. https://storybook.js.org/docs/writing-stories/mocking-data-and-modules/mocking-modules

  2. https://storybook.js.org/docs/writing-stories/mocking-data-and-modules/mocking-modules#using-automocked-modules-in-stories

@github-actions
Copy link

github-actions bot commented Dec 5, 2025

@georgerichmond
Copy link

Looking much better, simpler just to mock the hook 👍

Copy link
Contributor

@JamieB-gu JamieB-gu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks for making those changes, one question.

frequency: element.newsletter.frequency,
successDescription: element.newsletter.successDescription,
theme: element.newsletter.theme,
idApiUrl: idApiUrl ?? '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How will the component handle this when it's an empty string?

…nto 14890-show-or-hide-the-sign-up-newsletter-component
…nto 14890-show-or-hide-the-sign-up-newsletter-component
…nto 14890-show-or-hide-the-sign-up-newsletter-component
…nto 14890-show-or-hide-the-sign-up-newsletter-component
…nto 14890-show-or-hide-the-sign-up-newsletter-component
@Marianaguardian Marianaguardian added the run_chromatic Runs chromatic when label is applied label Dec 11, 2025
@github-actions github-actions bot removed the run_chromatic Runs chromatic when label is applied label Dec 11, 2025
@Marianaguardian Marianaguardian merged commit bfadeae into main Dec 11, 2025
29 checks passed
@Marianaguardian Marianaguardian deleted the 14890-show-or-hide-the-sign-up-newsletter-component branch December 11, 2025 13:21
@gu-prout
Copy link

gu-prout bot commented Dec 11, 2025

Seen on PROD (merged by @Marianaguardian 7 minutes and 56 seconds ago) Please check your changes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

show or hide the sign-up newsletter component

5 participants