Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions nuxt/assets/icons/arrows.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions nuxt/assets/icons/layers.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions nuxt/assets/icons/pin-slash.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions nuxt/assets/icons/pin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions nuxt/assets/icons/pulse.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions nuxt/assets/icons/snowflake.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions nuxt/assets/icons/target-view.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions nuxt/assets/icons/uns.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
84 changes: 48 additions & 36 deletions nuxt/components/HubSpotMeetings.vue
Original file line number Diff line number Diff line change
@@ -1,47 +1,61 @@
<script setup lang="ts">
// Ported from src/_includes/hubspot/hs-book-meeting.njk. Loading the meetings
// embed is gated behind analytics consent: src/js/cookieconsent-config.js
// (compiled into /js/cc.min.js, injected globally by nuxt/server/plugins/analytics.ts)
// calls window._ffLoadMeetings() from its onConsent/onFirstConsent handlers
// once analytics cookies are accepted - both on this page's load and on a
// later consent change. Until then, the fallback box below stays visible.
const props = defineProps<{
dataSrc: string
}>()
// src/_includes/hubspot/hs-book-meeting.njk plus the non-form branch of
// hubspot/consent-fallback.njk: the HubSpot meetings scheduler, with the "choose a time"
// panel that stands in for it.
//
// The embed is gated on analytics consent and MUST STAY THAT WAY. The .njk defined
// `window._ffLoadMeetings`, and src/js/cookieconsent-config.js calls it only once the
// visitor accepts; until then the embed is never injected. This registers the same global
// rather than loading on mount, so declining analytics still means no third-party
// scheduler script.
//
// The panel below is therefore not an error state: it is what a visitor who has not
// accepted analytics sees, and it gives them a way to book anyway. It is rendered
// unhidden and replaced once the embed is up, which is what the .njk did.
const props = defineProps<{ dataSrc: string }>()

const fallbackId = 'meetings-consent-placeholder'
const embedded = ref(false)

onMounted(() => {
(window as any)._ffLoadMeetings = function () {
const placeholder = document.getElementById(fallbackId)
if (!placeholder?.parentNode) return

const parent = placeholder.parentNode
type ConsentWindow = Window & {
_ffLoadMeetings?: (() => void) | null
CookieConsent?: { showPreferences: () => void }
}

const container = document.createElement('div')
container.className = 'meetings-iframe-container -mb-20 md:-mb-6'
container.setAttribute('data-src', props.dataSrc)
parent.insertBefore(container, placeholder)
function showCookiePreferences() {
;(window as ConsentWindow).CookieConsent?.showPreferences()
}

function loadEmbed() {
if (embedded.value) return
const existing = document.querySelector('script[src*="MeetingsEmbedCode.js"]')
if (!existing) {
const script = document.createElement('script')
script.src = 'https://static.hsappstatic.net/MeetingsEmbed/ex/MeetingsEmbedCode.js'
script.onload = () => { placeholder.remove() }
script.onerror = () => { placeholder.classList.remove('hidden') }
parent.insertBefore(script, placeholder)
;(window as any)._ffLoadMeetings = null
script.onload = () => { embedded.value = true }
document.head.appendChild(script)
} else {
embedded.value = true
}
}

// Registered for cookieconsent-config.js to call on accept, exactly as the .njk did.
// It also calls it on load when consent is already stored, so an existing acceptance is
// covered without this component reading cookies itself.
onMounted(() => {
;(window as ConsentWindow)._ffLoadMeetings = loadEmbed
})

onUnmounted(() => {
;(window as ConsentWindow)._ffLoadMeetings = null
})
</script>

<template>
<div>
<div :id="fallbackId" class="ff-hubspot-consent-fallback text-center border bg-indigo-900 rounded-lg px-6 pt-8 pb-4">
<h4 class="text-white font-medium">
Choose a time to talk
</h4>
<p class="text-indigo-200">
30-minute session with our team.
</p>
<div class="meetings-iframe-container -mb-20 md:-mb-6" :data-src="props.dataSrc" />
<div v-if="!embedded" class="ff-hubspot-consent-fallback text-center border bg-indigo-900 rounded-lg px-6 pt-8 pb-4">
<h4 class="text-white font-medium">Choose a time to talk</h4>
<p class="text-indigo-200">30-minute session with our team.</p>
<CtaCustom
label="Pick a time"
icon="i-lucide-arrow-right"
Expand All @@ -52,11 +66,9 @@ onMounted(() => {
/>
<p class="mt-4 text-indigo-200 italic font-xs">
Prefer to view availability on this page?<br>
<a
class="cursor-pointer text-indigo-200 underline"
type="button"
data-cc="show-preferencesModal"
>Enable analytics cookies.</a>
<button type="button" class="cursor-pointer text-indigo-200 underline bg-transparent border-0 p-0" @click="showCookiePreferences">
Enable analytics cookies.
</button>
</p>
</div>
</div>
Expand Down
Loading
Loading