/* Cumulative usage timer — after 10 min total, require sign-in to continue. */ const USAGE_KEY = 'fp-usage'; const LIMIT_MS = ((window.FP_CONFIG && window.FP_CONFIG.usageGateMinutes) || 10) * 60 * 1000; const TICK_MS = 1000; function readUsage() { try { const raw = localStorage.getItem(USAGE_KEY); if (!raw) return { totalMs: 0, signedIn: false, visitorId: null, name: '' }; const u = JSON.parse(raw); return { totalMs: Number(u.totalMs) || 0, signedIn: !!u.signedIn, visitorId: u.visitorId || null, name: u.name || '', }; } catch (_) { return { totalMs: 0, signedIn: false, visitorId: null, name: '' }; } } function writeUsage(u) { localStorage.setItem(USAGE_KEY, JSON.stringify(u)); } function ensureVisitorId(u) { if (u.visitorId) return u; const id = (typeof crypto !== 'undefined' && crypto.randomUUID) ? crypto.randomUUID() : ('v-' + Date.now() + '-' + Math.random().toString(36).slice(2, 9)); return { ...u, visitorId: id }; } function isAdminPath() { const p = (window.location.pathname || '').replace(/\/$/, ''); return p === '/admin'; } const UsageGateCtx = React.createContext(null); function useUsageGate() { return React.useContext(UsageGateCtx); } function SignInGateModal({ usage, onSuccess }) { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [phone, setPhone] = useState(''); const [busy, setBusy] = useState(false); const [err, setErr] = useState(''); async function submit(e) { e.preventDefault(); setErr(''); if (!name.trim() || !email.trim() || !phone.trim()) { setErr('Please fill in name, email, and phone.'); return; } setBusy(true); try { const res = await fetch('/api/auth/signin', { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, body: JSON.stringify({ name: name.trim(), email: email.trim(), phone: phone.trim(), visitorId: usage.visitorId, }), }); const data = await res.json().catch(() => ({})); if (!res.ok) throw new Error(data.error || 'Could not save sign-in'); onSuccess(name.trim()); } catch (ex) { setErr(ex.message || 'Something went wrong. Try again.'); } finally { setBusy(false); } } const mins = Math.floor(usage.totalMs / 60000); return (

Sign In to Continue

You've explored {mins}+ minutes of live market data. Enter your details to keep browsing Company Stock Price.

setName(e.target.value)} placeholder="Your name" autoComplete="name" /> setEmail(e.target.value)} placeholder="you@example.com" autoComplete="email" /> setPhone(e.target.value)} placeholder="+91 98765 43210" autoComplete="tel" /> {err &&
{err}
}

Free access · no password · your time is saved across visits on this device

); } function UsageGateProvider({ children }) { const bypass = isAdminPath(); const [usage, setUsage] = useState(() => ensureVisitorId(readUsage())); const [gateOpen, setGateOpen] = useState(() => { if (bypass) return false; const u = ensureVisitorId(readUsage()); return !u.signedIn && u.totalMs >= LIMIT_MS; }); useEffect(() => { if (bypass) return undefined; let u = ensureVisitorId(readUsage()); writeUsage(u); const tick = () => { if (document.visibilityState !== 'visible') return; u = readUsage(); if (u.signedIn) return; u.totalMs = (Number(u.totalMs) || 0) + TICK_MS; writeUsage(u); setUsage({ ...u }); if (u.totalMs >= LIMIT_MS) setGateOpen(true); }; const id = setInterval(tick, TICK_MS); const onVis = () => tick(); document.addEventListener('visibilitychange', onVis); return () => { clearInterval(id); document.removeEventListener('visibilitychange', onVis); }; }, [bypass]); function onSignedIn(name) { const u = { ...ensureVisitorId(readUsage()), signedIn: true, name: name || readUsage().name || '' }; writeUsage(u); setUsage(u); setGateOpen(false); } const value = { totalMs: usage.totalMs, signedIn: usage.signedIn, userName: usage.name || '', gateOpen: gateOpen && !usage.signedIn, limitMs: LIMIT_MS, }; return (
{children}
{gateOpen && !usage.signedIn && !bypass && ( )}
); } Object.assign(window, { UsageGateCtx, useUsageGate, UsageGateProvider, USAGE_LIMIT_MS: LIMIT_MS });