Skip to content

Commit 3dbf6ff

Browse files
committed
feat(core): allow customer subscription to Newsletter
1 parent abcb16a commit 3dbf6ff

3 files changed

Lines changed: 161 additions & 4 deletions

File tree

core/components/subscribe/_actions/subscribe.ts

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,32 @@
11
'use server';
22

3+
import { BigCommerceGQLError } from '@bigcommerce/catalyst-client';
34
import { SubmissionResult } from '@conform-to/react';
45
import { parseWithZod } from '@conform-to/zod';
56
import { getTranslations } from 'next-intl/server';
67

78
import { schema } from '@/vibes/soul/primitives/inline-email-form/schema';
9+
import { client } from '~/client';
10+
import { graphql } from '~/client/graphql';
11+
12+
const SubscribeToNewsletterMutation = graphql(`
13+
mutation SubscribeToNewsletterMutation($input: SubscribeToNewsletterInput!) {
14+
newsletter {
15+
subscribe(input: $input) {
16+
success
17+
errors {
18+
__typename
19+
... on CreateSubscriberEmailInvalidError {
20+
message
21+
}
22+
... on CreateSubscriberAlreadySubscribedError {
23+
message
24+
}
25+
}
26+
}
27+
}
28+
}
29+
`);
830

931
export const subscribe = async (
1032
_lastResult: { lastResult: SubmissionResult | null },
@@ -18,8 +40,59 @@ export const subscribe = async (
1840
return { lastResult: submission.reply() };
1941
}
2042

21-
// Simulate a network request
22-
await new Promise((resolve) => setTimeout(resolve, 1000));
43+
try {
44+
const response = await client.fetch({
45+
document: SubscribeToNewsletterMutation,
46+
variables: {
47+
input: {
48+
email: submission.value.email,
49+
},
50+
},
51+
fetchOptions: {
52+
cache: 'no-store',
53+
},
54+
});
55+
56+
if (response.data.success) {
57+
return { lastResult: submission.reply(), successMessage: t('success') };
58+
}
59+
60+
if (response.errors?.length > 0) {
61+
return {
62+
lastResult: submission.reply({
63+
formErrors: response.errors.map(({ __typename }) => {
64+
switch (__typename) {
65+
case 'CreateSubscriberAlreadySubscribedError':
66+
return t('Errors.subcriberAlreadyExists');
67+
68+
case 'CreateSubscriberEmailInvalidError':
69+
return t('Errors.invalidEmail');
2370

24-
return { lastResult: submission.reply(), successMessage: t('success') };
71+
default:
72+
return t('Errors.somethingWentWrong');
73+
}
74+
}),
75+
}),
76+
};
77+
}
78+
79+
return { lastResult: submission.reply({ formErrors: [t('Errors.somethingWentWrong')] }) };
80+
} catch (error) {
81+
// eslint-disable-next-line no-console
82+
console.error(error);
83+
84+
if (error instanceof BigCommerceGQLError) {
85+
return {
86+
lastResult: submission.reply({
87+
formErrors: error.errors.map(({ message }) => message),
88+
}),
89+
};
90+
}
91+
92+
if (error instanceof Error) {
93+
return { lastResult: submission.reply({ formErrors: [error.message] }) };
94+
}
95+
96+
return { lastResult: submission.reply({ formErrors: [t('Errors.somethingWentWrong')] }) };
97+
}
2598
};

core/messages/en.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,12 @@
504504
"title": "Sign up for our newsletter",
505505
"placeholder": "Enter your email",
506506
"description": "Stay up to date with the latest news and offers from our store.",
507-
"success": "Thank you for your interest! Newsletter feature is coming soon!"
507+
"success": "You have been subscribed to our newsletter.",
508+
"Errors": {
509+
"subcriberAlreadyExists": "You are already subscribed to our newsletter.",
510+
"invalidEmail": "Please enter a valid email address.",
511+
"somethingWentWrong": "Something went wrong. Please try again later."
512+
}
508513
},
509514
"ConsentManager": {
510515
"Common": {
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { faker } from '@faker-js/faker';
2+
3+
import { expect, test } from '~/tests/fixtures';
4+
import { getTranslations } from '~/tests/lib/i18n';
5+
import { TAGS } from '~/tests/tags';
6+
7+
test(
8+
'Successfully subscribes a user to the newsletter',
9+
{ tag: [TAGS.writesData] },
10+
async ({ page }) => {
11+
const t = await getTranslations('Components.Subscribe');
12+
13+
await page.goto('/');
14+
await page.waitForLoadState('networkidle');
15+
16+
const email = faker.internet.email();
17+
18+
const emailInput = page.getByPlaceholder(t('placeholder'));
19+
20+
await emailInput.fill(email);
21+
22+
const submitButton = page.locator('input[type="email"]').locator('..').getByRole('button');
23+
24+
await submitButton.click();
25+
await page.waitForLoadState('networkidle');
26+
27+
await expect(page.getByText(t('success'))).toBeVisible();
28+
},
29+
);
30+
31+
test('Shows error when email is invalid', async ({ page }) => {
32+
const t = await getTranslations('Components.Subscribe');
33+
34+
await page.goto('/');
35+
await page.waitForLoadState('networkidle');
36+
37+
const invalidEmail = 'not-an-email';
38+
39+
const emailInput = page.getByPlaceholder(t('placeholder'));
40+
41+
await emailInput.fill(invalidEmail);
42+
43+
const submitButton = page.locator('input[type="email"]').locator('..').getByRole('button');
44+
45+
await submitButton.click();
46+
await page.waitForLoadState('networkidle');
47+
48+
await expect(page.getByText(t('Errors.invalidEmail'))).toBeVisible();
49+
});
50+
51+
test(
52+
'Shows error when user tries to subscribe again with the same email',
53+
{ tag: [TAGS.writesData] },
54+
async ({ page }) => {
55+
const t = await getTranslations('Components.Subscribe');
56+
57+
await page.goto('/');
58+
await page.waitForLoadState('networkidle');
59+
60+
const email = faker.internet.email();
61+
62+
const emailInput = page.getByPlaceholder(t('placeholder'));
63+
const submitButton = page.locator('input[type="email"]').locator('..').getByRole('button');
64+
65+
// First subscription - should succeed
66+
await emailInput.fill(email);
67+
await submitButton.click();
68+
await page.waitForLoadState('networkidle');
69+
70+
await expect(page.getByText(t('success'))).toBeVisible();
71+
72+
// Try to subscribe again with the same email
73+
await emailInput.fill(email);
74+
await submitButton.click();
75+
await page.waitForLoadState('networkidle');
76+
77+
await expect(page.getByText(t('Errors.subcriberAlreadyExists'))).toBeVisible();
78+
},
79+
);

0 commit comments

Comments
 (0)