declare const Gmail: any import { v4 as uuid } from 'uuid' import { last, get, each, once } from 'lodash' const $: any = require('jquery') const Tether = require('tether') require('gmail-js') import * as email from './utils/email' import { IWrappedLinkResponse, IExtractedLink, IContentMainOptions, } from './utils/contentInterfaces' import { CLICK_TRACKING_URL } from './utils/ResourceConstants' import { toggleSendViaDrift, generateDriftComposeSelect, initialSendViaDriftState, updateStateOnRecipientChange, validateCallbackForCompose, tetherOpts, generateGmailBanner, generateTestEmailBody, } from './utils/contentMainHelpers' import { white_icon_src } from '../img/inlineImages' const driftComposeButtons: any[] = [] const enableDriftComposeButtons: any[] = [] let noop: boolean = false let gmail: any let tether: any let authStatus: boolean let currentUserEmail: string let onboardingId: any let contentMainOptions: IContentMainOptions = { orgId: null, userId: null, userName: null, avatarUrl: '', handle: null, bccStatus: false, bccEmailAddress: '', onboardingHyperlink: '', inboxesToRunExtensionOn: {}, meetingBaseUrl: '', } const emailUUIDPerComposeId: { [composeId: number]: string, } = {} const linksPerEmailUUID: { [uuid: string]: any, } = {} const wrapLinkCallbacks: { [id: string]: (data: IWrappedLinkResponse) => void, } = {} const latestCalendarAvailabilityCallbacks: { [id: string]: (data: any) => void, } = {} const gmailBanner = generateGmailBanner(white_icon_src) $($.parseHTML(gmailBanner)).insertAfter('.nH.w-asV.aiw') const gmailBannerClose = $('.drift-outbound-gmail-notification .close') gmailBannerClose.click(() => $('.drift-outbound-gmail-notification').hide()) const tooltip = $($.parseHTML(`

Drift tracking is only available for emails with a single recipient.

`)) const refresh = (f: any) => { if ((/in/.test(document.readyState)) || (typeof Gmail === undefined)) { setTimeout(() => refresh(f), 10) } else { f() } } const wrapLinks = (to: string, links: IExtractedLink[], callback: (data: IWrappedLinkResponse) => void) => { const id = uuid() wrapLinkCallbacks[id] = callback window.postMessage({ id, to, links, type: '@@driftext/wrap_links' }, '*') } const sendViaDrift = (compose: any) => () => { const composeId = compose.id() const emailUUID = uuid() emailUUIDPerComposeId[composeId] = emailUUID const recipients = compose.recipients() if (!recipients.to) { console.warn('No recipients, cannot send') return } if (onboardingId && (onboardingId === composeId)) { return compose.send() } const { bccStatus, bccEmailAddress } = contentMainOptions if (bccStatus && bccEmailAddress) { const newBcc = !!get(recipients, 'bcc.length') ? [...recipients.bcc, bccEmailAddress] : bccEmailAddress compose.bcc(newBcc) } const parsedRecipient = email.getTrackedEmail(recipients.to[0]) wrapLinks(parsedRecipient, email.extractLinksToReplace(compose, emailUUID), ({ to, wrappedLinks }: IWrappedLinkResponse) => { if (validateCallbackForCompose(compose, parsedRecipient, to)) { if (wrappedLinks.length) { linksPerEmailUUID[emailUUID] = wrappedLinks compose.body(email.replaceLinksWithWrappedLinks(compose.body(), wrappedLinks)) } compose.body(compose.body() + ``) compose.send() } }) } const instrumentCompose = (compose: any) => { if (noop) { return } if (!get(contentMainOptions.inboxesToRunExtensionOn, currentUserEmail, false)) { return } const composeId = compose.id() // add a 'Send via Drift' button driftComposeButtons.push(gmail.tools.add_compose_button(compose, 'Send with Drift', sendViaDrift(compose), `drift-send`)) enableDriftComposeButtons.push(gmail.tools.add_compose_button(compose, generateDriftComposeSelect(composeId), toggleSendViaDrift(compose), `drift-compose-select`)) if (!tether && document.querySelector(`.drift-outbound-checkbox-label-${composeId}`)) { try { tether = new Tether(tetherOpts(composeId)) } catch (e) { window.postMessage({ error: `content-main-error: ${e.message}`, type: '@@driftext/capture_error' }, '*') } $(`.drift-outbound-tooltip`).hide() } $('.Ha').click(() => $(`.drift-outbound-tooltip`).hide()) initialSendViaDriftState(compose, authStatus, tether) } const messageEventHandler = (event: any) => { if (event.source !== window || !event.data.type || noop) { return } switch (event.data.type) { case '@@driftext/update_auth_status': authStatus = event.data.authStatus if (!get(contentMainOptions.inboxesToRunExtensionOn, currentUserEmail, false)) { return } gmail.dom.composes().forEach((compose: any) => { initialSendViaDriftState(compose, authStatus, tether) }) break case '@@driftext/update_content_main_options': contentMainOptions = event.data.contentMainOptions if (!get(contentMainOptions.inboxesToRunExtensionOn, currentUserEmail, false)) { return } setupExtension() break case '@@driftext/wrapped_links': const { id, to, wrappedLinks } = event.data if (wrapLinkCallbacks[id]) { wrapLinkCallbacks[id] && Promise.resolve({ to, wrappedLinks }).then(wrapLinkCallbacks[id]) delete wrapLinkCallbacks[id] } else { console.warn(`No send callback for id ${id}`) } break case '@@driftext/latest_calendar_availability': const { data } = event.data const callbackId = event.data.id if (latestCalendarAvailabilityCallbacks[callbackId]) { latestCalendarAvailabilityCallbacks[callbackId] && Promise.resolve(data).then(latestCalendarAvailabilityCallbacks[callbackId]) delete latestCalendarAvailabilityCallbacks[callbackId] } else { console.warn(`No send callback for id ${callbackId}`) } break case '@@driftext/show_modal': $('#drift-outbound-banner-email').text(event.data.email || 'the notification') $('.drift-outbound-gmail-notification').css('display', 'flex') break case '@@driftext/reset_script': noop = true each(driftComposeButtons, button => $(button) && $(button).remove()) each(enableDriftComposeButtons, button => $(button) && $(button).remove()) break case '@@driftext/create_test_email': const isGmailReady = setInterval(() => { if (!!gmail) { clearInterval(isGmailReady) gmail.compose.start_compose() setTimeout(() => { const compose = last(gmail.dom.composes()) as any compose.to('hi@drift.com') compose.subject('Drift Extension') compose.body(generateTestEmailBody(contentMainOptions.onboardingHyperlink)) $('.editable').click() onboardingId = compose.id() }, 700) } }) break } } window.addEventListener('message', messageEventHandler, false) const setupExtension = once(() => { $('.aAU').append(tooltip) $(`.drift-outbound-tooltip`).click(() => $('.drift-outbound-tooltip').hide()) gmail.observe.on('recipient_change', (compose: any) => { if (noop) { return } updateStateOnRecipientChange(compose, authStatus) }) !noop && gmail.dom.composes().forEach(instrumentCompose) gmail.observe.on('compose', instrumentCompose) gmail.observe.before('send_message', () => { $(`.drift-outbound-tooltip`).hide() }) gmail.observe.after('send_message', (url: any, body: any, data: any, response: any, xhr: any) => { try { if (noop) { return } const composeId = data.composeid const emailUUID = emailUUIDPerComposeId[composeId] // early exit if the email wasn't sent with drift if (!emailUUID) { return } const subject = data.subject const parsedRecipient = email.getTrackedEmail(data.to[0]) const linksToPatch = linksPerEmailUUID[emailUUID] const gmailId = email.getGmailIdFromResponse(response) if (!gmailId) { window.postMessage({ senderEmail: currentUserEmail, type: '@@driftext/extract_gmail_id_failed' }, '*') } else if (linksToPatch) { window.postMessage({ emailUUID, gmailId, clickIds: linksToPatch, type: '@@driftext/patch_click_tracks_with_email_id' }, '*') } if (onboardingId && (onboardingId === composeId) && parsedRecipient === 'hi@drift.com') { window.postMessage({ gmailId, subject, type: '@@driftext/onboarding_email_sent' }, '*') } window.postMessage({ emailUUID, gmailId, subject, endUserEmail: parsedRecipient, type: '@@driftext/sent_email' }, '*') delete linksPerEmailUUID[emailUUID] delete emailUUIDPerComposeId[composeId] } catch (error) { window.postMessage({ error: `content-main-error: ${error.message}`, type: '@@driftext/capture_error' }, '*') } }) }) const main = () => { gmail = new Gmail($) currentUserEmail = gmail.get.user_email() window.postMessage({ email: currentUserEmail, type: '@@driftext/ready' }, '*') } refresh(main)