import { authLogger, type Logger } from '@/observability/logging' import { loggerWithMaybeContext } from '@/observability/utils/requestContext' import { addToMailchimpAudience } from '@/modules/auth/services/mailchimp' import { UserEvents } from '@/modules/core/domain/users/events' import { enableMixpanel, getMailchimpNewsletterIds, getMailchimpOnboardingIds, getMailchimpStatus } from '@/modules/shared/helpers/envHelper' import { EventBus, EventPayload } from '@/modules/shared/services/eventBus' import { mixpanel } from '@/modules/shared/utils/mixpanel' import { UpdateUserMixpanelProfile } from '@/modules/core/domain/users/operations' import { DependenciesOf } from '@/modules/shared/helpers/factory' const onUserCreatedFactory = (deps: { updateUserMixpanelProfileFactory: UpdateUserMixpanelProfile }) => async (payload: EventPayload) => { const logger = loggerWithMaybeContext({ logger: authLogger }) const { user, signUpCtx } = payload.payload try { // Send event to MP const userEmail = user.email const newsletterConsent = signUpCtx?.newsletterConsent if (userEmail && enableMixpanel()) { const isInvite = !!signUpCtx?.isInvite await mixpanel({ userEmail, req: signUpCtx?.req }).track('Sign Up', { isInvite }) } // Set up mailchimp if (getMailchimpStatus()) { try { const { listId: onboardingListId } = getMailchimpOnboardingIds() await addToMailchimpAudience(user, onboardingListId) if (newsletterConsent) { const { listId: newsletterListId } = getMailchimpNewsletterIds() await addToMailchimpAudience(user, newsletterListId) } } catch (error) { logger.warn({ err: error }, 'Failed to sign up user to mailchimp lists') } } // Update MP profile await deps.updateUserMixpanelProfileFactory({ userId: user.id }) } catch (e) { logger.error( { err: e, userId: user.id }, 'Post sign up tracking failed' ) } } const onUserAuthenticatedFactory = (deps: { updateUserMixpanelProfileFactory: UpdateUserMixpanelProfile }) => async (payload: EventPayload) => { const logger = loggerWithMaybeContext({ logger: authLogger }) const { userId, isNewUser } = payload.payload // We already did this once on user creation if (isNewUser) return try { // Update MP profile await deps.updateUserMixpanelProfileFactory({ userId }) } catch (e) { logger.error( { err: e, userId }, 'Post sign in tracking failed' ) } } const onUserUpdatedFactory = (deps: { updateUserMixpanelProfileFactory: UpdateUserMixpanelProfile }) => async (payload: EventPayload) => { const logger = loggerWithMaybeContext({ logger: authLogger }) const { oldUser: { id: userId } } = payload.payload try { // Update MP profile await deps.updateUserMixpanelProfileFactory({ userId }) } catch (e) { logger.error( { err: e, userId }, 'Post user update tracking failed' ) } } export const reportUserEventsFactory = ( deps: { eventBus: EventBus; logger: Logger } & DependenciesOf< typeof onUserCreatedFactory > & DependenciesOf & DependenciesOf ) => () => { const onUserCreated = onUserCreatedFactory(deps) const onUserAuthenticated = onUserAuthenticatedFactory(deps) const onUserUpdated = onUserUpdatedFactory(deps) const cbs = [ deps.eventBus.listen(UserEvents.Created, onUserCreated), deps.eventBus.listen(UserEvents.Authenticated, onUserAuthenticated), deps.eventBus.listen(UserEvents.Updated, onUserUpdated) ] return () => cbs.forEach((cb) => cb()) }