108 lines
3.1 KiB
JavaScript
108 lines
3.1 KiB
JavaScript
import { ref } from 'vue'
|
|
|
|
// Wraps Klaviyo's legacy client-side list-subscribe endpoint.
|
|
// Klaviyo requires any non-standard property names to be declared in `$fields`
|
|
// for them to be persisted on the profile — this composable handles that for you.
|
|
|
|
const ENDPOINT = 'https://manage.kmail-lists.com/ajax/subscriptions/subscribe'
|
|
|
|
export default () => {
|
|
const loading = ref(false)
|
|
const success = ref(false)
|
|
const error = ref('')
|
|
|
|
const reset = () => {
|
|
loading.value = false
|
|
success.value = false
|
|
error.value = ''
|
|
}
|
|
|
|
const subscribe = async ({
|
|
listId,
|
|
email,
|
|
firstName,
|
|
lastName,
|
|
name,
|
|
source,
|
|
properties = {},
|
|
} = {}) => {
|
|
if (!listId) {
|
|
error.value = 'Missing listId'
|
|
return
|
|
}
|
|
if (!email) {
|
|
error.value = 'Missing email'
|
|
return
|
|
}
|
|
|
|
loading.value = true
|
|
error.value = ''
|
|
|
|
// `name` is a convenience: first token → first_name, rest → last_name
|
|
let fName = firstName
|
|
let lName = lastName
|
|
if (name && !fName && !lName) {
|
|
const parts = name.trim().split(/\s+/)
|
|
fName = parts.shift()
|
|
lName = parts.join(' ') || undefined
|
|
}
|
|
|
|
const body = { g: listId, email }
|
|
if (fName) body.first_name = fName
|
|
if (lName) body.last_name = lName
|
|
|
|
const extraFields = []
|
|
if (source) {
|
|
body.$source = source
|
|
extraFields.push('$source')
|
|
}
|
|
for (const [key, value] of Object.entries(properties)) {
|
|
if (value === undefined || value === null || value === '') continue
|
|
body[key] = value
|
|
extraFields.push(key)
|
|
}
|
|
if (extraFields.length) body.$fields = extraFields.join(',')
|
|
|
|
try {
|
|
await $fetch(ENDPOINT, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'Cache-Control': 'no-cache',
|
|
},
|
|
body: new URLSearchParams(body),
|
|
})
|
|
success.value = true
|
|
} catch (err) {
|
|
console.error('useKlaviyo subscribe error', err)
|
|
error.value =
|
|
err?.toString().split('Error: ')[1] || 'Subscription failed'
|
|
}
|
|
|
|
loading.value = false
|
|
}
|
|
|
|
// Fires a Klaviyo event (metric) — append-only history, good for things
|
|
// segments will slice on like "Submitted RSVP" with per-event properties.
|
|
// Throws on failure; doesn't touch the shared loading/success/error refs,
|
|
// so callers can pair it with subscribe() without state collisions.
|
|
const track = ({ email, metric, properties = {} }) => {
|
|
if (!email || !metric) {
|
|
throw new Error('useKlaviyo.track: email and metric are required')
|
|
}
|
|
return $fetch('/api/klaviyo-track', {
|
|
method: 'POST',
|
|
body: { email, metric, properties },
|
|
})
|
|
}
|
|
|
|
return {
|
|
loading,
|
|
success,
|
|
error,
|
|
subscribe,
|
|
track,
|
|
reset,
|
|
}
|
|
}
|