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(`
`))
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)