audiobookshelf/client/plugins/achievement-hooks.client.js
2025-09-10 06:53:19 +00:00

74 lines
2.6 KiB
JavaScript

// client/plugins/achievement-hooks.client.js
import AchievementService from '@/services/AchievementService'
export default ({ app }, inject) => {
const seen = new Set()
const once = async (key, fn) => {
try {
if (seen.has(key)) return
seen.add(key)
await fn()
} catch (_) {}
}
// --------------------- DAILY LOGIN PING (UTC-day safe) --------------------
const todayKey = () => Math.floor(Date.now() / (24 * 60 * 60 * 1000)) // UTC-ish
const storageKey = () => `abs:login-ping:${todayKey()}`
const trySendDailyLoginPing = async () => {
const k = storageKey()
if (sessionStorage.getItem(k)) return
// Ensure we are authenticated before we count a login
const me = await AchievementService.getMy().catch(() => null)
if (me && me.userId && me.userId !== 'guest') {
await AchievementService.complete({ event: 'userLoggedIn' })
sessionStorage.setItem(k, '1')
}
}
if (process.browser) {
// fire on app load and after each route change (first successful auth wins)
trySendDailyLoginPing()
app.router.afterEach(() => trySendDailyLoginPing())
// also check again every ~15 minutes in long-lived tabs crossing midnight
setInterval(() => trySendDailyLoginPing(), 15 * 60 * 1000)
}
// -------------------------- NAVIGATION HOOKS ------------------------------
app.router.afterEach((to) => {
// Upload page
if (to.path.startsWith('/upload')) {
once('visitedUpload', () => AchievementService.complete({ event: 'visitedUpload' }))
}
// Authors
if (to.path.startsWith('/author') || to.path.startsWith('/authors')) {
once('openedAuthor', () => AchievementService.complete({ event: 'openedAuthor' }))
}
// Narrators
if (to.path.startsWith('/narrator') || to.path.startsWith('/narrators')) {
once('openedNarrator', () => AchievementService.complete({ event: 'openedNarrator' }))
}
// Stats pages (Your Stats / Library Stats)
if (to.path.startsWith('/stats') || to.path.startsWith('/your-stats') || to.path.startsWith('/library-stats')) {
once('visitedSettings', () => AchievementService.complete({ event: 'visitedSettings' }))
}
})
// ------------------------ OPTIONAL ACTION HOOKS ---------------------------
if (process.browser) {
window.addEventListener('abs:search-performed', () => {
AchievementService.complete({ event: 'performedSearch' })
})
window.addEventListener('abs:playlist-created', () => {
AchievementService.complete({ event: 'createdPlaylist' })
})
window.addEventListener('abs:book-downloaded', () => {
AchievementService.complete({ event: 'downloadedBook' })
})
}
}