Port modular price, product, and PWA fixes into boursecu
Sync live quote handling, SSE product images, store hours, file URL normalization, PWA icon cache, TV monitor, about software, SuperAdmin menu gates, price alerts, and related UX from modular while preserving boursecu branding and config constraints. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import {
|
||||
computed,
|
||||
inject,
|
||||
onMounted,
|
||||
provide,
|
||||
ref,
|
||||
type ComputedRef,
|
||||
type InjectionKey,
|
||||
type Ref,
|
||||
} from 'vue'
|
||||
import {
|
||||
fetchTrackingSettings,
|
||||
resolveTrackingSystems,
|
||||
type TrackingSystemSite,
|
||||
} from '@/utils/trackingSystemsSettings'
|
||||
|
||||
export type ReygiriSite = TrackingSystemSite
|
||||
|
||||
export interface RecoverySitesPageContext {
|
||||
sites: Ref<ReygiriSite[]>
|
||||
loading: Ref<boolean>
|
||||
isEmpty: ComputedRef<boolean>
|
||||
openSite: (url: string) => void
|
||||
}
|
||||
|
||||
export const RECOVERY_SITES_PAGE_CONTEXT_KEY: InjectionKey<RecoverySitesPageContext> =
|
||||
Symbol('recoverySitesPageContext')
|
||||
|
||||
function normalizeExternalUrl(url: string) {
|
||||
const trimmed = url.trim()
|
||||
if (!trimmed) {
|
||||
return ''
|
||||
}
|
||||
if (/^https?:\/\//i.test(trimmed)) {
|
||||
return trimmed
|
||||
}
|
||||
return `https://${trimmed.replace(/^\/\//, '')}`
|
||||
}
|
||||
|
||||
export function useRecoverySitesPage() {
|
||||
const sites = ref<ReygiriSite[]>([])
|
||||
const loading = ref(false)
|
||||
const isEmpty = computed(() => !loading.value && sites.value.length === 0)
|
||||
|
||||
async function loadSites() {
|
||||
loading.value = true
|
||||
try {
|
||||
const settings = await fetchTrackingSettings(true)
|
||||
sites.value = resolveTrackingSystems(settings)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
sites.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void loadSites()
|
||||
})
|
||||
|
||||
function openSite(url: string) {
|
||||
const normalized = normalizeExternalUrl(url)
|
||||
if (!normalized) {
|
||||
return
|
||||
}
|
||||
window.open(normalized, '_blank', 'noopener,noreferrer')
|
||||
}
|
||||
|
||||
const context: RecoverySitesPageContext = {
|
||||
sites,
|
||||
loading,
|
||||
isEmpty,
|
||||
openSite,
|
||||
}
|
||||
|
||||
provide(RECOVERY_SITES_PAGE_CONTEXT_KEY, context)
|
||||
return context
|
||||
}
|
||||
|
||||
export function useRecoverySitesPageContext() {
|
||||
const context = inject(RECOVERY_SITES_PAGE_CONTEXT_KEY)
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'useRecoverySitesPageContext must be used within a page that calls useRecoverySitesPage()',
|
||||
)
|
||||
}
|
||||
return context
|
||||
}
|
||||
Reference in New Issue
Block a user