Skip to content
Open
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
16 changes: 11 additions & 5 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@
</head>
<body>
<div id="app">
<button id="track_goal" type="button" disabled>track goal event</button>
<button id="flush" type="button" disabled>flush events</button>
<button id="set_user_attributes" type="button">set user attributes</button>
<button id="view_user_attributes" type="button"> view user attributes</button>
<div id="logs" style="border: 1px solid black; margin-top: 8px;"></div>
<div style="margin-bottom: 8px; display: flex; gap: 8px; align-items: center;">
<button id="init" type="button">Initialize</button>
<button id="destroy" type="button" disabled>Destroy</button>
</div>
<div style="margin-bottom: 8px; display: flex; gap: 8px;">
<button id="track_goal" type="button" disabled>track goal event</button>
<button id="flush" type="button" disabled>flush events</button>
<button id="set_user_attributes" type="button">set user attributes</button>
<button id="view_user_attributes" type="button">view user attributes</button>
Comment thread
duyhungtnn marked this conversation as resolved.
</div>
<div id="logs" style="border: 1px solid #ccc; padding: 8px; font-family: monospace; min-height: 200px; max-height: 400px; overflow-y: auto;"></div>
</div>
<script type="module">
import start from './index.ts'
Expand Down
168 changes: 100 additions & 68 deletions example/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,106 +10,138 @@ const FEATURE_TAG = 'feature-tag' // replace here
const STRING_FEATURE_ID = 'feature_id' // replace here
const GOAL_ID = 'goal_id' // replace here

const AUTO_INIT_FLAG = true

export default async function start(root: HTMLElement) {
const logsEl = root.querySelector('#logs')
const buttonEl = root.querySelector('#track_goal')
const flushEl = root.querySelector('#flush')
const setUserAttributesEl = root.querySelector('#set_user_attributes')
const viewUserAttributesEl = root.querySelector('#view_user_attributes')
const buttonEl = root.querySelector<HTMLButtonElement>('#track_goal')
const flushEl = root.querySelector<HTMLButtonElement>('#flush')
const setUserAttributesEl = root.querySelector<HTMLButtonElement>('#set_user_attributes')
const viewUserAttributesEl = root.querySelector<HTMLButtonElement>('#view_user_attributes')
const initEl = root.querySelector<HTMLButtonElement>('#init')
const destroyEl = root.querySelector<HTMLButtonElement>('#destroy')

let listenerId: string | null | undefined = null
let initializing = false

function log(message: string) {
if (logsEl) {
logsEl.innerHTML += message + '<br/>'
const logLine = document.createElement('div')
logLine.textContent = `[${new Date().toLocaleTimeString()}] ${message}`
logsEl.appendChild(logLine)
logsEl.scrollTop = logsEl.scrollHeight
}
Comment thread
duyhungtnn marked this conversation as resolved.
console.log(message)
}

buttonEl?.addEventListener('click', () => {
getBKTClient()?.track(GOAL_ID, 1 /* goal value */)
log('goal tracked')
function updateButtons(initialized: boolean) {
if (buttonEl) buttonEl.disabled = !initialized
if (flushEl) flushEl.disabled = !initialized
Comment thread
duyhungtnn marked this conversation as resolved.
if (initEl) initEl.disabled = initialized
if (destroyEl) destroyEl.disabled = !initialized
}

const handleInit = async () => {
if (initializing) return
initializing = true
if (initEl) initEl.disabled = true
const config = defineBKTConfig({
apiEndpoint: import.meta.env.VITE_BKT_API_ENDPOINT,
apiKey: import.meta.env.VITE_BKT_API_KEY,
featureTag: FEATURE_TAG,
appVersion: '1.2.3',
fetch: window.fetch,
})

const user = defineBKTUser({
id: 'user_id_1',
})

log('Initializing BKTClient...')
try {
await initializeBKTClient(config, user)
initializing = false
log('Initialization completed')
updateButtons(true)

const client = getBKTClient()
const value = client?.stringVariation(STRING_FEATURE_ID, 'default_value')
log(`Value for ${STRING_FEATURE_ID}: ${value}`)

listenerId = client?.addEvaluationUpdateListener(() => {
log('Evaluation updated')
const newValue = client?.stringVariation(STRING_FEATURE_ID, 'default_value')
log(`Value for ${STRING_FEATURE_ID}: ${newValue}`)
Comment thread
duyhungtnn marked this conversation as resolved.
})
} catch (error) {
initializing = false
log(`Initialization failed: ${error}`)
Comment thread
duyhungtnn marked this conversation as resolved.
listenerId = null
destroyBKTClient()
updateButtons(false)
Comment thread
duyhungtnn marked this conversation as resolved.
}
}

const handleDestroy = () => {
log('Destroying BKTClient...')
if (listenerId) {
getBKTClient()?.removeEvaluationUpdateListener(listenerId)
listenerId = null
}
destroyBKTClient()
log('BKTClient destroyed')
updateButtons(false)
}

initEl?.addEventListener('click', handleInit)
destroyEl?.addEventListener('click', handleDestroy)

buttonEl?.addEventListener('click', async () => {
try {
await getBKTClient()?.track(GOAL_ID, 1)
log('Goal tracked')
} catch (error) {
log(`Track failed: ${error}`)
}
Comment thread
duyhungtnn marked this conversation as resolved.
})

flushEl?.addEventListener('click', () => {
const client = getBKTClient()
if (client) {
// you can always force-send saved events
const flushPromise = client.flush()
log('flushing...')
flushPromise
.then(() => log('flushed'))
.catch((error) => log(`flush failed: ${error}`))
log('Flushing events...')
client.flush()
.then(() => log('Flushed'))
.catch((error) => log(`Flush failed: ${error}`))
}
})

setUserAttributesEl?.addEventListener('click', () => {
setUserAttributesEl?.addEventListener('click', async () => {
const client = getBKTClient()
if (client) {
// you can set custom attributes for the user
client.updateUserAttributes({ kYear: 'value_2025' })
log('user attributes set')
try {
await client.updateUserAttributes({ kYear: 'value_2025' })
log('User attributes updated')
} catch (error) {
log(`Update user attributes failed: ${error}`)
}
}
})

viewUserAttributesEl?.addEventListener('click', () => {
const client = getBKTClient()
if (client) {
// you can view current user attributes
const user = client.currentUser()
log(`current user attributes: ${JSON.stringify(user.attributes)}`)
log(`Current user attributes: ${JSON.stringify(user.attributes)}`)
}
})

const config = defineBKTConfig({
apiEndpoint: import.meta.env.VITE_BKT_API_ENDPOINT,
apiKey: import.meta.env.VITE_BKT_API_KEY,
featureTag: FEATURE_TAG,
appVersion: '1.2.3',
fetch: window.fetch,
})

const user = defineBKTUser({
id: 'user_id_1',
// you can also set custom attributes
// customAttributes: { key: 'value'}
})

log('initialize BKTClient')

const initialFetchPromise = initializeBKTClient(config, user)

initialFetchPromise
.then(() => {
log('initialization completed')
buttonEl?.removeAttribute('disabled')
flushEl?.removeAttribute('disabled')

const value = getBKTClient()?.stringVariation(
STRING_FEATURE_ID,
'default_value',
)
log(`value for feature_id: ${value}`)
})
.catch((error) => {
log(`initialization failed: ${error}`)
})

window.addEventListener('beforeunload', () => {
log('destroy BKTClient')
if (listenerId) {
getBKTClient()?.removeEvaluationUpdateListener(listenerId)
}
destroyBKTClient()
handleDestroy()
})

log('fetching evaluations...')

const client = getBKTClient()

listenerId = client?.addEvaluationUpdateListener(() => {
log('evaluation updated')
const value = client?.stringVariation(STRING_FEATURE_ID, 'default_value')
log(`value for feature_id: ${value}`)
})
if (AUTO_INIT_FLAG) {
handleInit()
} else {
log('Auto-init disabled. Click "Initialize" to start.')
}
}
Loading