How can I add Newsletter in PWA Magento2 ?
1 Answer
This code is to add newsletter in the footer, the code is based on venia concept package. change as per your need.
Here you have to create REST Api module for newsletter in Magento, there is free module available you can use that https://github.com/regento/magento2-newsletter-api
Import Newsletter in Footer: src/components/Footer/footer.js
import Newsletter from '../Newsletter';
// Add below code in render() Method
<div className={classes.newsletter}>
<Newsletter />
</div>
Create Newsletter Component, src/components/Newsletter/index.js
export { default as Newsletter } from './newsletter';
export { default } from './container';
src/components/Newsletter/newsletter.js
import React, { Component } from 'react';
import { func, shape, string } from 'prop-types';
import defaultClasses from './newsletter.css';
import classify from 'src/classify';
import Field from '../Field';
import Button from '../Button';
import { Form } from 'informed';
import TextInput from '../TextInput';
import Icon from '../Icon';
import MailIcon from 'react-feather/dist/icons/mail';
import combine from 'src/util/combineValidators';
import { validateEmail, isRequired } from 'src/util/formValidators';
class Newsletter extends Component {
static propTypes = {
classes: shape({
actions: string,
error: string,
lead: string,
root: string,
form: string,
subscribe: string,
signUp: string,
signUpTitle: string,
signUpText: string,
inputField: string,
signUpPolicy: string,
successMessage: string,
inProgressMessage: string,
errorMessage: string
}),
createAccountError: shape({
message: string
}),
initialValues: shape({
email: string,
firstName: string,
lastName: string
})
};
static defaultProps = {
initialValues: {}
};
get errorMessage() {
const { createAccountError } = this.props;
if (createAccountError) {
const errorIsEmpty = Object.keys(createAccountError).length === 0;
if (!errorIsEmpty) {
return 'An error occurred. Please try again.';
}
}
}
get initialValues() {
const { initialValues } = this.props;
const { email, firstName, lastName, ...rest } = initialValues;
return {
customer: { email, firstname: firstName, lastname: lastName },
...rest
};
}
handleFormSubmit = async ({ email }) => {
this.props.signUpForNewsletter({ email });
};
render() {
const { errorMessage, initialValues, props } = this;
const { classes, isError, isInProgress, isSuccess } = props;
const mail = <Icon src={MailIcon} size={16} />;
if (isInProgress) {
return (
<div className={classes.root}>
<p className={classes.inProgressMessage}>
Sending your request...
</p>
</div>
);
}
if (isError) {
return (
<div className={classes.root}>
<p className={classes.errorMessage}>
Looks like you have already signed up, Thanks!
</p>
</div>
);
}
if (isSuccess) {
return (
<div className={classes.root}>
<p className={classes.successMessage}>
Thanks for signing up for our newsletter
</p>
<small className={classes.signUpPolicy}>
emails are subject to our
<a href="/privacy-policy"> Privacy Policy</a>
</small>
</div>
);
}
return (
<div className={classes.root}>
<h2 className={classes.signUpTitle}>Let's keep in touch</h2>
<p className={classes.signUpText}>
<span>
Stay up-to-date with our newest products and best deals
</span>
</p>
<div className={classes.inputField}>
<Form
className={classes.form}
initialValues={initialValues}
onSubmit={this.handleFormSubmit}
>
<Field label="Email" required={true}>
<TextInput
field="email"
autoComplete="email"
validate={combine([isRequired, validateEmail])}
validateOnBlur
placeholder="Email"
label="Email"
before={mail}
/>
</Field>
<div className={classes.error}>{errorMessage}</div>
<div className={classes.actions}>
<Button type="submit" priority="high">
{'Submit'}
</Button>
</div>
</Form>
</div>
<small className={classes.signUpPolicy}>
emails are subject to our
<a href="/privacy-policy"> Privacy Policy</a>
</small>
</div>
);
}
}
export default classify(defaultClasses)(Newsletter);
src/components/Newsletter/container.js
import { connect } from 'src/drivers';
import Newsletter from './newsletter';
import { signUpForNewsletter } from 'src/actions/newsletter';
const mapStateToProps = ({ newsletter }) => {
const { isInProgress, isError, isSuccess } = newsletter;
return {
isInProgress,
isError,
isSuccess
};
};
const mapDispatchToProps = {
signUpForNewsletter
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Newsletter);
src/actions/newsletter/actions.js
import { createActions } from 'redux-actions';
const prefix = 'NEWSLETTER';
const actionMap = {
SIGN_UP_FOR_NEWSLETTER: {
REQUEST: null,
RECEIVE: null
},
NEWSLETTER_ERROR: {
REQUEST: null,
RECEIVE: null
}
};
export default createActions(actionMap, { prefix });
src/actions/newsletter/asyncActions.js
import { RestApi } from '@magento/peregrine';
import actions from './actions';
const { request } = RestApi.Magento2;
export const signUpForNewsletter = ({ email }) =>
async function thunk(...args) {
const [dispatch] = args;
dispatch(actions.signUpForNewsletter.request(email));
const body = {
email: email
};
const response = await request('rest/V1/newsletter/subscribe', {
method: 'POST',
body: JSON.stringify(body)
});
console.log('newsletter action response', response);
if (response.success == true) {
await dispatch(actions.signUpForNewsletter.receive(response));
}
if (response.success == false) {
await dispatch(actions.newsletterError.receive(response));
}
};
src/actions/newsletter/index.js
export { default } from './actions';
export * from './asyncActions';
src/reducers/index.js
import newsletter from './newsletter';
// Add in combineReducers
export default combineReducers({
newsletter
});
src/reducers/newsletter.js
import { handleActions } from 'redux-actions';
import actions from '../actions/newsletter';
export const name = 'newsletter';
const initialState = {
isInProgress: false,
isError: false,
isSuccess: false
};
const reducerMap = {
[actions.signUpForNewsletter.request]: state => {
return {
...state,
isInProgress: true,
isError: false
};
},
[actions.signUpForNewsletter.receive]: state => {
return {
...state,
isInProgress: false,
isSuccess: true
};
},
[actions.newsletterError.receive]: state => {
return {
...state,
isInProgress: false,
isError: true
};
}
};
export default handleActions(reducerMap, initialState);
src/components/Newsletter/newsletter.css
Add your CSS in this file
And it works, Hope this help.
-
Hello @Ashish I installed module as per instructions. I installed in venia-ui. I am getting following error. Can u guide me on this? Uncaught TypeError: Cannot destructure property 'isInProgress' of 'newsletter' as it is undefined.– ArjunCommented Aug 19, 2020 at 4:46
-
-
-
Than this code will not work, you will need to modify, this is for older version. Commented Aug 20, 2020 at 5:39
-
Hello @Ashish I managed to set it in my version. Just wanted to know from where is the Newsletter email being fired? I am getting email of subscriber. But not able to get place from where they are getting fired.– ArjunCommented Aug 21, 2020 at 11:28