Files
speckle-server/packages/server/modules/auth/services/mailchimp.ts
T
andrewwallacespeckle 2f17b3f8b8 fix(server): Remove mailchimp step and journey ids (#4750)
* fix(server): Remove mailchimp step and journey ids

* Fix pre-commit - add end

* feat(server): use both onboardin and newsletter list audiences

* Fix type

* Remove unused triggerMailchimpCustomerJourney function

---------

Co-authored-by: Gergő Jedlicska <gergo@jedlicska.com>
2025-05-15 12:24:50 +02:00

100 lines
2.9 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'
import { MailchimpResourceError } from '@/modules/auth/errors'
import { ensureError } from '@speckle/shared'
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
}
export 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
}
})
}
export 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 (e) {
throw new MailchimpResourceError(
'User not found in Mailchimp audience. They should have been added during registration.',
{
info: { userEmailHash: subscriberHash },
cause: ensureError(e, 'Mailchimp API error')
}
)
}
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
})
}