// InstallPrompt — add-to-home-screen entry points: cabinet banner, // header icon button, iOS instructions sheet. // State machine lives in /a2hs.js (plain JS, loaded before React). const { useState: useA2hsState, useEffect: useA2hsEffect } = React; function useA2HS() { const [, force] = useA2hsState(0); useA2hsEffect(() => { if (!window.a2hs) return undefined; const unsub = window.a2hs.subscribe(() => force(x => x + 1)); // Re-check once: beforeinstallprompt may have fired in the gap between // the first render and this effect — that notify() had no subscribers. force(x => x + 1); return unsub; }, []); // No hard dependency on the plain script: if /a2hs.js failed to load // (partial deploy, blocking extension), render no install UI instead of // throwing and blanking the whole SPA. if (!window.a2hs) return { state: 'unavailable', dismissed: true }; return { state: window.a2hs.getState(), dismissed: window.a2hs.isDismissed() }; } function a2hsActivate(state) { if (state === 'installable') window.a2hs.prompt(); // never rejects (caught inside a2hs.js) else if (state === 'ios') window.dispatchEvent(new CustomEvent('a2hs-open-guide')); } function InstallBanner() { const { state, dismissed } = useA2HS(); if (dismissed || (state !== 'installable' && state !== 'ios')) return null; return (
Добавьте авито.пф на главный экран
Быстрый доступ к заказам и балансу — в одно касание
); } function InstallHeaderButton() { const { state, dismissed } = useA2HS(); // Same gate as the banner: ✕ / «Готово, добавил» set the dismissed flag and // both entry points disappear together. appinstalled clears the flag, so // after an uninstall the icon can return. if (dismissed || (state !== 'installable' && state !== 'ios')) return null; return ( ); } function InstallGuideSheet() { const [open, setOpen] = useA2hsState(false); // Permanent listener: opens the sheet on the CustomEvent from a2hsActivate. useA2hsEffect(() => { const h = () => setOpen(true); window.addEventListener('a2hs-open-guide', h); return () => window.removeEventListener('a2hs-open-guide', h); }, []); // Escape + body scroll-lock only while the sheet is actually open, so the // global keydown handler isn't bound for the whole session. useA2hsEffect(() => { if (!open) return undefined; const onKey = e => { if (e.key === 'Escape') setOpen(false); }; window.addEventListener('keydown', onKey); const prevOverflow = document.body.style.overflow; document.body.style.overflow = 'hidden'; return () => { window.removeEventListener('keydown', onKey); document.body.style.overflow = prevOverflow; }; }, [open]); if (!open) return null; const done = () => { if (window.a2hs) window.a2hs.dismiss(); setOpen(false); }; return (
setOpen(false)}>
e.stopPropagation()}>
); }