Website: add newsletter subscription form to homepage (#23362)
Related to: #23212 Changes: - Added a form to the homepage for users to subscribe to the Fleet newsletter. - Updated the unsubscribe-from-all-newsletters action to redirect users to the fleet homepage once they are unsubscribed from the newsletter. - Updated the update-or-create-one-newsletter-subscription action to create/update CRM records when users sign up for the Fleet newsletter.
This commit is contained in:
@@ -13,12 +13,6 @@ module.exports = {
|
||||
required: true,
|
||||
},
|
||||
|
||||
subscribeTo: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The type of content that this user is changing their subscription for',
|
||||
isIn: ['releases']
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -28,24 +22,39 @@ module.exports = {
|
||||
description: 'A user has successfully changed their subscription to the Fleet newsletter'
|
||||
},
|
||||
|
||||
invalidEmailDomain: {
|
||||
description: 'This email address is on a denylist of domains and was not delivered.',
|
||||
responseType: 'badRequest'
|
||||
},
|
||||
|
||||
|
||||
},
|
||||
|
||||
|
||||
fn: async function ({emailAddress, subscribeTo}) {
|
||||
|
||||
fn: async function ({emailAddress}) {
|
||||
|
||||
let emailDomain = emailAddress.split('@')[1];
|
||||
if(_.includes(sails.config.custom.bannedEmailDomainsForWebsiteSubmissions, emailDomain.toLowerCase())){
|
||||
throw 'invalidEmailDomain';
|
||||
}
|
||||
await NewsletterSubscription.create({emailAddress: emailAddress})
|
||||
.tolerate('E_UNIQUE');
|
||||
|
||||
let argins = {};
|
||||
await NewsletterSubscription.updateOne({emailAddress: emailAddress}).set({isSubscribedToReleases: true});
|
||||
|
||||
// Update the NewsletterSubscription record for this email address with `isSubscribedTo____` boolean attributes based on the subscribeTo input
|
||||
if(subscribeTo === 'releases') {
|
||||
argins.isSubscribedToReleases = true;
|
||||
}
|
||||
// FUTURE: Handle more types of subscribeTo inputs
|
||||
|
||||
await NewsletterSubscription.updateOne({emailAddress: emailAddress}).set(argins);
|
||||
sails.helpers.salesforce.updateOrCreateContactAndAccount.with({
|
||||
emailAddress: emailAddress,
|
||||
contactSource: 'Website - Newsletter',
|
||||
description: `Subscribed to the Fleet newsletter`,
|
||||
psychologicalStage: '3 - Intrigued',
|
||||
psychologicalStageChangeReason: 'Website - Newsletter',
|
||||
}).exec((err)=>{// Use .exec() to run the salesforce helpers in the background.
|
||||
if(err) {
|
||||
sails.log.warn(`Background task failed: When a user signed up for a newsletter, a lead/contact could not be updated in the CRM for this email address: ${emailAddress}.`, err);
|
||||
}
|
||||
return;
|
||||
});
|
||||
|
||||
// All done.
|
||||
return;
|
||||
|
||||
@@ -35,7 +35,7 @@ module.exports = {
|
||||
sails.log.warn('When a user tried to unsubscribe from the Fleet newsletter, a NewsletterSubscription record for the specified email address ('+ emailAddress +') could not be found.');
|
||||
}
|
||||
// All done.
|
||||
return;
|
||||
return this.res.redirect('/#unsubscribed');
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ module.exports = {
|
||||
linkedinUrl: { type: 'string' },
|
||||
|
||||
// Set…
|
||||
firstName: { type: 'string', required: true },
|
||||
lastName: { type: 'string', required: true },
|
||||
firstName: { type: 'string'},
|
||||
lastName: { type: 'string'},
|
||||
organization: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
primaryBuyingSituation: { type: 'string' },
|
||||
@@ -39,6 +39,7 @@ module.exports = {
|
||||
isIn: [
|
||||
'Website - Contact forms',
|
||||
'Website - Sign up',
|
||||
'Website - Newsletter',
|
||||
],
|
||||
},
|
||||
getStartedResponses: {
|
||||
@@ -237,8 +238,8 @@ module.exports = {
|
||||
.create({
|
||||
AccountId: salesforceAccountId,
|
||||
OwnerId: salesforceAccountOwnerId,
|
||||
FirstName: firstName,
|
||||
LastName: lastName,
|
||||
FirstName: firstName ? firstName : '?',
|
||||
LastName: lastName ? lastName : '?',
|
||||
...valuesToSet,
|
||||
});
|
||||
// console.log(`Created ${newContactRecord.id}`);
|
||||
|
||||
+22
-2
@@ -4,7 +4,20 @@ parasails.registerPage('homepage', {
|
||||
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
|
||||
data: {
|
||||
modal: undefined,
|
||||
selectedCategory: 'mdm'
|
||||
selectedCategory: 'mdm',
|
||||
formData: { /* … */ },
|
||||
formErrors: { /* … */ },
|
||||
|
||||
// Form rules
|
||||
formRules: {
|
||||
emailAddress: {isEmail: true, required: true},
|
||||
},
|
||||
|
||||
syncing: false,
|
||||
|
||||
// Server error state for the form
|
||||
cloudError: '',
|
||||
cloudSuccess: false,
|
||||
},
|
||||
|
||||
// ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗
|
||||
@@ -33,6 +46,13 @@ parasails.registerPage('homepage', {
|
||||
closeModal: function() {
|
||||
this.modal = undefined;
|
||||
},
|
||||
|
||||
submittedNewsletterForm: async function() {
|
||||
// Show the success message.
|
||||
this.cloudSuccess = true;
|
||||
this.formData = {};
|
||||
await setTimeout(()=>{
|
||||
this.cloudSuccess = false;
|
||||
}, 10000);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
+110
-2
@@ -708,7 +708,61 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[purpose='newsletter-banner'] {
|
||||
width: 660px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 32px;
|
||||
margin-bottom: 32px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #E2E4EA;
|
||||
background: #F9FAFC;
|
||||
display: block;
|
||||
padding: 8px 8px 8px 16px;
|
||||
input {
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--ui-fleet-blue-15, #E2E4EA);
|
||||
background: var(--Core-White, #FFF);
|
||||
display: flex;
|
||||
width: 235px;
|
||||
padding: 8px 15px;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
align-self: stretch;
|
||||
height: 37px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
p {
|
||||
color: #515774;
|
||||
margin-bottom: 0px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 21px;
|
||||
}
|
||||
[purpose='subscribe-button'] {
|
||||
color: #FFF;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
align-self: stretch;
|
||||
border-radius: 4px;
|
||||
background: #FF5C83;
|
||||
height: 37px;
|
||||
width: 92px;
|
||||
/* Body XS (bold) */
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 18px; /* 150% */
|
||||
}
|
||||
[purpose='newsletter-form-input']::placeholder {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
[purpose='video-modal'] {
|
||||
[purpose='modal-dialog'] {
|
||||
width: 100%;
|
||||
@@ -1229,7 +1283,61 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[purpose='newsletter-banner'] {
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #E2E4EA;
|
||||
background: #F9FAFC;
|
||||
display: block;
|
||||
padding: 16px;
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
input {
|
||||
border-radius: 6px;
|
||||
border: 1px solid #E2E4EA;
|
||||
background: #FFF;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 8px 15px;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
align-self: stretch;
|
||||
height: 37px;
|
||||
margin-right: 0px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
p {
|
||||
color: #515774;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 21px;
|
||||
}
|
||||
[purpose='subscribe-button'] {
|
||||
color: #FFF;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
align-self: stretch;
|
||||
border-radius: 4px;
|
||||
background: #FF5C83;
|
||||
height: 37px;
|
||||
width: 100%;
|
||||
font-family: Inter;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 18px; /* 150% */
|
||||
}
|
||||
[purpose='newsletter-form-input']::placeholder {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
[purpose='video-modal'] {
|
||||
[purpose='modal-dialog'] {
|
||||
max-width: 97vw;
|
||||
|
||||
Vendored
+1
@@ -518,6 +518,7 @@ module.exports.routes = {
|
||||
'GET /g': (req,res)=> { let originalQueryStringWithAmp = req.url.match(/\?(.+)$/) ? '&'+req.url.match(/\?(.+)$/)[1] : ''; return res.redirect(301, sails.config.custom.baseUrl+'/?meet-fleet'+originalQueryStringWithAmp); },
|
||||
'GET /test-fleet-sandbox': '/register',
|
||||
'GET /unsubscribe': (req,res)=> { let originalQueryString = req.url.match(/\?(.+)$/) ? req.url.match(/\?(.+)$/)[1] : ''; return res.redirect(301, sails.config.custom.baseUrl+'/api/v1/unsubscribe-from-marketing-emails?'+originalQueryString);},
|
||||
'GET /unsubscribe-from-newsletter': (req,res)=> { let originalQueryString = req.url.match(/\?(.+)$/) ? req.url.match(/\?(.+)$/)[1] : ''; return res.redirect(301, sails.config.custom.baseUrl+'/api/v1/unsubscribe-from-all-newsletters?'+originalQueryString);},
|
||||
'GET /tables': '/tables/account_policy_data',
|
||||
'GET /imagine/launch-party': 'https://www.eventbrite.com/e/601763519887',
|
||||
'GET /blackhat2023': 'https://github.com/fleetdm/fleet/tree/main/tools/blackhat-mdm', // Assets from @marcosd4h & @zwass Black Hat 2023 talk
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
<p>© <%= (new Date()).getFullYear() %> Fleet Device Management Inc. All trademarks, service marks, and company names are the property of their respective owners.</p>
|
||||
</div>
|
||||
<div>
|
||||
<p style="font-size: 12px; color: #3E4771;">You received this email because you’re subscribed to the Fleet newsletter. <a href="<%= url.resolve(sails.config.custom.baseUrl, '/unsubscribe?emailAddress='+encodeURIComponent(emailAddress)) %>">Unsubscribe</a></p>
|
||||
<p style="font-size: 12px; color: #3E4771;">You received this email because you’re subscribed to the Fleet newsletter. <a href="<%= url.resolve(sails.config.custom.baseUrl, '/unsubscribe-from-newsletter?emailAddress='+encodeURIComponent(emailAddress)) %>">Unsubscribe</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Vendored
+19
@@ -405,6 +405,25 @@
|
||||
</div>
|
||||
<%/* Cloud city banner */%>
|
||||
<parallax-city></parallax-city>
|
||||
<div purpose="homepage-content" class="container py-4 my-0 my-md-2">
|
||||
<div purpose="newsletter-banner">
|
||||
<div class="d-flex flex-md-row flex-column justify-content-between">
|
||||
<div purpose="newletter-form-text" class="d-flex flex-row align-items-center">
|
||||
<p v-if="formErrors.emailAddress || cloudError" class="text-danger" focus-first>Please enter a valid work email</p>
|
||||
<p v-else-if="cloudSuccess">Thanks for subscribing!</p>
|
||||
<p v-else><strong>Curious?</strong> Get product updates and news</p>
|
||||
</div>
|
||||
<ajax-form class="d-flex flex-md-row flex-column" action="createOrUpdateOneNewsletterSubscription" :form-errors.sync="formErrors" :form-data="formData" :form-rules="formRules" :syncing.sync="syncing" :cloud-error.sync="cloudError" @submitted="submittedNewsletterForm()">
|
||||
<div class="d-flex flex-column w-100">
|
||||
<input purpose="newsletter-form-input" class="form-control" v-model.trim="formData.emailAddress" placeholder="Enter your work email">
|
||||
</div>
|
||||
<div class="d-flex flex-column w-100">
|
||||
<ajax-button purpose="subscribe-button" type="submit-button" :syncing="syncing" class="btn btn-primary">Subscribe</ajax-button>
|
||||
</div>
|
||||
</ajax-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<modal v-if="modal === 'unsubscribed'" @close="closeModal()">
|
||||
<p class="mb-0">Your email preferences have been updated.</p>
|
||||
</modal>
|
||||
|
||||
Reference in New Issue
Block a user