138 lines
5.0 KiB
TypeScript
138 lines
5.0 KiB
TypeScript
import { ref, readonly } from 'vue'
|
|
import type { AlbionPriceEntry, AlbionCity, ManualPriceEntry, ManualPriceCache } from '../types/api'
|
|
|
|
// ─── Override duration ────────────────────────────────────────────────────────
|
|
|
|
export const OVERRIDE_DURATION_OPTIONS: { label: string; ms: number }[] = [
|
|
{ label: '30 min', ms: 30 * 60 * 1000 },
|
|
{ label: '1 hour', ms: 60 * 60 * 1000 },
|
|
{ label: '2 hours', ms: 2 * 60 * 60 * 1000 },
|
|
{ label: '4 hours', ms: 4 * 60 * 60 * 1000 },
|
|
{ label: '8 hours', ms: 8 * 60 * 60 * 1000 },
|
|
{ label: '24 hours',ms: 24 * 60 * 60 * 1000 },
|
|
]
|
|
|
|
const DURATION_STORAGE_KEY = 'albion-override-duration'
|
|
const MANUAL_STORAGE_KEY = 'albion-manual-prices'
|
|
|
|
function loadOverrideDuration(): number {
|
|
try {
|
|
const raw = localStorage.getItem(DURATION_STORAGE_KEY)
|
|
if (raw) {
|
|
const ms = Number(raw)
|
|
if (OVERRIDE_DURATION_OPTIONS.some(o => o.ms === ms)) return ms
|
|
}
|
|
} catch { /* ignore */ }
|
|
return 24 * 60 * 60 * 1000 // default 24 hours
|
|
}
|
|
|
|
function loadManualPricesFromStorage(): ManualPriceCache {
|
|
try {
|
|
const raw = localStorage.getItem(MANUAL_STORAGE_KEY)
|
|
if (raw) {
|
|
const obj = JSON.parse(raw) as Record<string, ManualPriceEntry>
|
|
return new Map(Object.entries(obj))
|
|
}
|
|
} catch { /* ignore */ }
|
|
return new Map()
|
|
}
|
|
|
|
function saveManualPricesToStorage(map: ManualPriceCache): void {
|
|
try {
|
|
const obj: Record<string, ManualPriceEntry> = {}
|
|
for (const [key, val] of map) obj[key] = val
|
|
localStorage.setItem(MANUAL_STORAGE_KEY, JSON.stringify(obj))
|
|
} catch { /* ignore */ }
|
|
}
|
|
|
|
// ─── Module-level singleton state ────────────────────────────────────────────
|
|
|
|
const manualPrices = ref<ManualPriceCache>(loadManualPricesFromStorage())
|
|
const overrideDurationMs = ref<number>(loadOverrideDuration())
|
|
|
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
|
|
function cacheKey(itemId: string, city: string): string {
|
|
return `${itemId}::${city}`
|
|
}
|
|
|
|
function isManualExpired(entry: ManualPriceEntry): boolean {
|
|
return Date.now() - new Date(entry.editedAt).getTime() > overrideDurationMs.value
|
|
}
|
|
|
|
function synthesizeManualEntry(
|
|
entry: ManualPriceEntry,
|
|
itemId: string,
|
|
city: AlbionCity,
|
|
): AlbionPriceEntry {
|
|
return {
|
|
item_id: itemId,
|
|
city,
|
|
quality: 1,
|
|
sell_price_min: entry.sell_price_min,
|
|
sell_price_min_date: entry.editedAt,
|
|
sell_price_max: entry.sell_price_min,
|
|
buy_price_min: 0,
|
|
buy_price_max: 0,
|
|
}
|
|
}
|
|
|
|
// ─── Price accessors ──────────────────────────────────────────────────────────
|
|
|
|
function getPrice(itemId: string, city: AlbionCity): AlbionPriceEntry | null {
|
|
const key = cacheKey(itemId, city)
|
|
const manual = manualPrices.value.get(key)
|
|
if (manual && !isManualExpired(manual)) {
|
|
return synthesizeManualEntry(manual, itemId, city)
|
|
}
|
|
return null
|
|
}
|
|
|
|
// ─── Manual price management ──────────────────────────────────────────────────
|
|
|
|
function setManualPrice(itemId: string, city: AlbionCity, price: number): void {
|
|
const key = cacheKey(itemId, city)
|
|
const next = new Map(manualPrices.value)
|
|
next.set(key, { sell_price_min: price, editedAt: new Date().toISOString() })
|
|
manualPrices.value = next
|
|
saveManualPricesToStorage(next)
|
|
}
|
|
|
|
function clearManualPrice(itemId: string, city: AlbionCity): void {
|
|
const key = cacheKey(itemId, city)
|
|
if (!manualPrices.value.has(key)) return
|
|
const next = new Map(manualPrices.value)
|
|
next.delete(key)
|
|
manualPrices.value = next
|
|
saveManualPricesToStorage(next)
|
|
}
|
|
|
|
function isManualPrice(itemId: string, city: AlbionCity): boolean {
|
|
const entry = manualPrices.value.get(cacheKey(itemId, city))
|
|
return !!entry && !isManualExpired(entry)
|
|
}
|
|
|
|
function getManualEntry(itemId: string, city: AlbionCity): ManualPriceEntry | undefined {
|
|
const entry = manualPrices.value.get(cacheKey(itemId, city))
|
|
return entry && !isManualExpired(entry) ? entry : undefined
|
|
}
|
|
|
|
function setOverrideDuration(ms: number): void {
|
|
overrideDurationMs.value = ms
|
|
try { localStorage.setItem(DURATION_STORAGE_KEY, String(ms)) } catch { /* ignore */ }
|
|
}
|
|
|
|
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
|
|
export function useAlbionPrices() {
|
|
return {
|
|
overrideDurationMs: readonly(overrideDurationMs),
|
|
getPrice,
|
|
setManualPrice,
|
|
clearManualPrice,
|
|
isManualPrice,
|
|
getManualEntry,
|
|
setOverrideDuration,
|
|
}
|
|
}
|