Files
ERP_Distribution/distribution_fe/components/shared/top-loader.tsx
T
Kalana B. Thilakarathna 28c465f59b
CI/CD - ERP Distribution / Build & Deploy Backend (pull_request) Failing after 10m33s
CI/CD - ERP Distribution / Build & Deploy Frontend (pull_request) Failing after 14m21s
feat: refactor TopLoader to use a hook for active state management and improve CSS for fixed positioning
2026-10-19 23:37:45 +05:30

48 lines
1.3 KiB
TypeScript

'use client'
import { useEffect, useState, useSyncExternalStore } from 'react'
// Global ref-count store. Any page can call useTopLoader(active) and the
// shared <TopLoader /> (mounted once in the dashboard layout) will reflect it.
let activeCount = 0
const listeners = new Set<() => void>()
function emit() { listeners.forEach(l => l()) }
function subscribe(cb: () => void) { listeners.add(cb); return () => { listeners.delete(cb) } }
function getSnapshot() { return activeCount }
export function useTopLoader(active: boolean) {
useEffect(() => {
if (!active) return
activeCount += 1
emit()
return () => {
activeCount = Math.max(0, activeCount - 1)
emit()
}
}, [active])
}
// Short tail so a sub-100ms fetch still shows the strip briefly.
const TAIL_MS = 350
export function TopLoader() {
const count = useSyncExternalStore(subscribe, getSnapshot, () => 0)
const [tailing, setTailing] = useState(false)
useEffect(() => {
if (count > 0) { setTailing(true); return }
const t = setTimeout(() => setTailing(false), TAIL_MS)
return () => clearTimeout(t)
}, [count])
if (count === 0 && !tailing) return null
return (
<div className="top-loader" aria-hidden="true">
<div className="top-loader__bar">
<span className="top-loader__head" />
</div>
</div>
)
}