snipe/web/src/stores/preferences.ts
pyr0ball 8e40e51ed3
Some checks are pending
CI / Frontend typecheck + tests (push) Waiting to run
CI / Python tests (push) Waiting to run
Mirror / mirror (push) Waiting to run
Release / release (push) Waiting to run
fix: prefix /api/session and /api/preferences with VITE_API_BASE
Both stores hardcoded /api/* paths without reading VITE_API_BASE, causing
/api/session to hit the menagerie root (no /snipe prefix) and receive a
302 redirect to circuitforge.tech/login instead of a session response.
Every other store already read VITE_API_BASE correctly.
2026-04-16 12:51:39 -07:00

80 lines
2.1 KiB
TypeScript

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useSessionStore } from './session'
export interface UserPreferences {
affiliate?: {
opt_out?: boolean
byok_ids?: {
ebay?: string
}
}
}
const apiBase = (import.meta.env.VITE_API_BASE as string) ?? ''
export const usePreferencesStore = defineStore('preferences', () => {
const session = useSessionStore()
const prefs = ref<UserPreferences>({})
const loading = ref(false)
const error = ref<string | null>(null)
const affiliateOptOut = computed(() => prefs.value.affiliate?.opt_out ?? false)
const affiliateByokId = computed(() => prefs.value.affiliate?.byok_ids?.ebay ?? '')
async function load() {
if (!session.isLoggedIn) return
loading.value = true
error.value = null
try {
const res = await fetch(`${apiBase}/api/preferences`)
if (res.ok) {
prefs.value = await res.json()
}
} catch {
// Non-cloud deploy or network error — preferences unavailable
} finally {
loading.value = false
}
}
async function setPref(path: string, value: boolean | string | null) {
if (!session.isLoggedIn) return
error.value = null
try {
const res = await fetch(`${apiBase}/api/preferences`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ path, value }),
})
if (res.ok) {
prefs.value = await res.json()
} else {
const data = await res.json().catch(() => ({}))
error.value = data.detail ?? 'Failed to save preference.'
}
} catch {
error.value = 'Network error saving preference.'
}
}
async function setAffiliateOptOut(value: boolean) {
await setPref('affiliate.opt_out', value)
}
async function setAffiliateByokId(id: string) {
// Empty string clears the BYOK ID (router falls back to CF env var)
await setPref('affiliate.byok_ids.ebay', id.trim() || null)
}
return {
prefs,
loading,
error,
affiliateOptOut,
affiliateByokId,
load,
setAffiliateOptOut,
setAffiliateByokId,
}
})