8c69f22e27
* Add new updateMailchimpMemberTags function and use it in FE * Pass tag data from FE * Plan > Use case * move onboarding types to shared package * Check newsletter consent * Changes from PR * GQL
119 lines
3.2 KiB
TypeScript
119 lines
3.2 KiB
TypeScript
/* eslint-disable camelcase */
|
|
import mailchimp from '@mailchimp/mailchimp_marketing'
|
|
import { md5 } from '@/modules/shared/helpers/cryptoHelper'
|
|
import { getMailchimpConfig } from '@/modules/shared/helpers/envHelper'
|
|
import { UserRecord } from '@/modules/core/helpers/types'
|
|
import { MisconfiguredEnvironmentError } from '@/modules/shared/errors'
|
|
import { OnboardingCompletionInput } from '@/modules/core/graph/generated/graphql'
|
|
|
|
let mailchimpInitialized = false
|
|
|
|
function initializeMailchimp() {
|
|
if (mailchimpInitialized) return
|
|
const config = getMailchimpConfig() // Note: throws an error if not configured
|
|
if (!config)
|
|
throw new MisconfiguredEnvironmentError(
|
|
'Cannot initialize mailchimp without config values'
|
|
)
|
|
|
|
mailchimp.setConfig({
|
|
apiKey: config.apiKey,
|
|
server: config.serverPrefix
|
|
})
|
|
mailchimpInitialized = true
|
|
}
|
|
|
|
async function addToMailchimpAudience(user: UserRecord, listId: string) {
|
|
initializeMailchimp()
|
|
// Do not do anything (inc. logging) if we do not explicitly enable it
|
|
// Note: fails here should not block registration at any cost
|
|
|
|
const [first, second] = user.name.split(' ')
|
|
const subscriberHash = md5(user.email.toLowerCase())
|
|
|
|
// NOTE: using setListMember (NOT addListMember) to prevent errors for previously
|
|
// registered members.
|
|
await mailchimp.lists.setListMember(listId, subscriberHash, {
|
|
status_if_new: 'subscribed',
|
|
email_address: user.email,
|
|
merge_fields: {
|
|
EMAIL: user.email,
|
|
FNAME: first,
|
|
LNAME: second,
|
|
FULLNAME: user.name // NOTE: this field needs to be set in the audience merge fields
|
|
}
|
|
})
|
|
}
|
|
|
|
async function triggerMailchimpCustomerJourney(
|
|
user: UserRecord,
|
|
{
|
|
listId,
|
|
journeyId,
|
|
stepId
|
|
}: {
|
|
listId: string
|
|
journeyId: number
|
|
stepId: number
|
|
}
|
|
) {
|
|
await addToMailchimpAudience(user, listId)
|
|
// @ts-expect-error the mailchimp api typing sucks
|
|
await mailchimp.customerJourneys.trigger(journeyId, stepId, {
|
|
email_address: user.email
|
|
})
|
|
}
|
|
|
|
async function updateMailchimpMemberTags(
|
|
user: UserRecord,
|
|
listId: string,
|
|
onboardingData: OnboardingCompletionInput
|
|
) {
|
|
initializeMailchimp()
|
|
const subscriberHash = md5(user.email.toLowerCase())
|
|
|
|
// Check if user is already in audience (meaning they consented to marketing emails)
|
|
try {
|
|
await mailchimp.lists.getListMember(listId, subscriberHash)
|
|
} catch {
|
|
throw new Error(
|
|
`User ${user.email} not found in Mailchimp audience. They should have been added during registration.`
|
|
)
|
|
}
|
|
|
|
const tags: { name: string; status: 'active' | 'inactive' }[] = []
|
|
|
|
if (onboardingData.role) {
|
|
tags.push({
|
|
name: `Role: ${onboardingData.role}`,
|
|
status: 'active'
|
|
})
|
|
}
|
|
|
|
if (onboardingData.plans?.length) {
|
|
onboardingData.plans.forEach((plan) => {
|
|
tags.push({
|
|
name: `Use case: ${plan}`,
|
|
status: 'active'
|
|
})
|
|
})
|
|
}
|
|
|
|
if (onboardingData.source) {
|
|
tags.push({
|
|
name: `Source: ${onboardingData.source}`,
|
|
status: 'active'
|
|
})
|
|
}
|
|
|
|
await mailchimp.lists.updateListMemberTags(listId, subscriberHash, {
|
|
tags
|
|
})
|
|
}
|
|
|
|
export {
|
|
addToMailchimpAudience,
|
|
triggerMailchimpCustomerJourney,
|
|
updateMailchimpMemberTags
|
|
}
|