sozsoft-platform/ui/src/views/version/installPrompt.ts
2026-08-12 22:08:14 +03:00

87 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Tarayıcının "uygulamayı yükle" akışı (PWA install).
*
* `beforeinstallprompt` sayfa yüklenirken erken tetiklenir; React ağacı mount
* olmadan yakalanmazsa olay kaybolur ve buton hiç görünmez. Bu yüzden modül
* import edilir edilmez dinleyiciler kurulur (dosya ~1 KB, entry'de kalması
* sorun değil).
*/
type InstallPromptEvent = Event & {
prompt: () => Promise<void>
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>
}
export type InstallState = {
/** Tarayıcı kurulum teklifi verdi ve uygulama henüz kurulu değil. */
canInstall: boolean
/** Uygulama standalone modda çalışıyor (yani kurulu). */
installed: boolean
}
let deferredPrompt: InstallPromptEvent | undefined
const isStandalone = () => {
try {
return (
window.matchMedia('(display-mode: standalone)').matches ||
window.matchMedia('(display-mode: minimal-ui)').matches ||
(navigator as unknown as { standalone?: boolean }).standalone === true
)
} catch {
return false
}
}
let state: InstallState = { canInstall: false, installed: isStandalone() }
const listeners = new Set<(value: InstallState) => void>()
export const getInstallState = () => state
export const subscribeInstallState = (listener: (value: InstallState) => void) => {
listeners.add(listener)
return () => listeners.delete(listener)
}
function setState(patch: Partial<InstallState>) {
state = { ...state, ...patch }
listeners.forEach((listener) => listener(state))
}
export const promptAppInstall = async (): Promise<'accepted' | 'dismissed' | 'unavailable'> => {
const event = deferredPrompt
if (!event) return 'unavailable'
// Yakalanan olay tek kullanımlıktır.
deferredPrompt = undefined
setState({ canInstall: false })
try {
await event.prompt()
const { outcome } = await event.userChoice
if (outcome === 'accepted') setState({ installed: true })
return outcome
} catch (error) {
console.warn('Uygulama kurulumu başlatılamadı.', error)
return 'unavailable'
}
}
if (typeof window !== 'undefined') {
window.addEventListener('beforeinstallprompt', (event) => {
// Varsayılan mini bar yerine uygulama içindeki butonu kullanıyoruz.
event.preventDefault()
deferredPrompt = event as InstallPromptEvent
setState({ canInstall: !isStandalone(), installed: isStandalone() })
})
window.addEventListener('appinstalled', () => {
deferredPrompt = undefined
setState({ canInstall: false, installed: true })
})
window
.matchMedia('(display-mode: standalone)')
.addEventListener?.('change', (event) =>
setState({ installed: event.matches, canInstall: event.matches ? false : state.canInstall }),
)
}