import React from 'react'; import { View, Text, StyleSheet, Pressable } from 'react-native'; import { BellRing, X } from 'lucide-react-native'; import Button from './Button'; import { spacing, radius, typography, type ThemePalette } from '../theme/tokens'; import { useColors } from '../theme/colors'; import { useAuthStore } from '../stores/auth-store'; import { useLocaleStore } from '../stores/locale-store'; import { useSettingsStore } from '../stores/settings-store'; import { DEFAULT_RELAY_BASE_URL, dismissPushPrompt, getEffectiveRelayBaseUrl, isPushEnabledForAccount, isPushSupported, PushSetupError, setStoredRelayBaseUrl, setupPushNotifications, wasPushPromptDismissed, } from '../lib/push-notifications'; // Mirrors the webmail's push-notification-prompt: a short delay after login // so the inbox renders first, and never again for an account once dismissed. const PROMPT_DELAY_MS = 1500; /** * Once-per-account invitation to turn on background notifications. Shown * only where push can actually work (Android with Play services), when the * user has not disabled mail notifications, and until either "Enable" or * "Not now" has been tapped for the active account. */ export function PushOnboardingPrompt(): React.ReactElement | null { const c = useColors(); const styles = React.useMemo(() => makeStyles(c), [c]); const t = useLocaleStore((s) => s.t); const isAuthenticated = useAuthStore((s) => s.isAuthenticated); const client = useAuthStore((s) => s.client); const activeAccountId = useAuthStore((s) => s.activeAccountId); const username = useAuthStore((s) => s.username); const emailNotificationsEnabled = useSettingsStore((s) => s.emailNotificationsEnabled); const [visible, setVisible] = React.useState(false); const [busy, setBusy] = React.useState(false); const [error, setError] = React.useState(null); React.useEffect(() => { setVisible(false); setError(null); if (!isAuthenticated || !client || !activeAccountId || !emailNotificationsEnabled) return; if (!isPushSupported()) return; let cancelled = false; const timer = setTimeout(() => { void (async () => { if (await wasPushPromptDismissed(activeAccountId)) return; if (await isPushEnabledForAccount(activeAccountId)) return; if (!cancelled) setVisible(true); })(); }, PROMPT_DELAY_MS); return () => { cancelled = true; clearTimeout(timer); }; }, [isAuthenticated, client, activeAccountId, emailNotificationsEnabled]); if (!visible || !activeAccountId) return null; const handleDismiss = () => { setVisible(false); void dismissPushPrompt(activeAccountId); }; const handleEnable = async () => { setBusy(true); setError(null); try { const relayBaseUrl = (await getEffectiveRelayBaseUrl()) || DEFAULT_RELAY_BASE_URL; await setStoredRelayBaseUrl(relayBaseUrl); await setupPushNotifications({ relayBaseUrl, accountLabel: username ?? undefined }); await dismissPushPrompt(activeAccountId); setVisible(false); } catch (err) { const message = err instanceof PushSetupError || err instanceof Error ? err.message : t('settings.notifications.push.setup_failed', 'Setup failed'); setError(message); } finally { setBusy(false); } }; return ( {t('push_prompt.title', 'Get notified about new mail')} {t( 'push_prompt.body', 'Turn on background notifications so new messages reach you while the app is closed.', )} {error && {error}} ); } function makeStyles(c: ThemePalette) { return StyleSheet.create({ card: { flexDirection: 'row', alignItems: 'flex-start', gap: spacing.md, marginHorizontal: spacing.md, marginTop: spacing.sm, padding: spacing.md, borderRadius: radius.md, borderWidth: 1, borderColor: c.border, backgroundColor: c.card, }, iconWrap: { width: 36, height: 36, borderRadius: radius.full, backgroundColor: c.primaryBg, alignItems: 'center', justifyContent: 'center', }, title: { ...typography.bodyMedium, color: c.text }, body: { ...typography.caption, color: c.mutedForeground, marginTop: 2 }, error: { ...typography.caption, color: c.error, marginTop: spacing.xs }, actions: { flexDirection: 'row', gap: spacing.sm, marginTop: spacing.sm }, close: { padding: 2 }, }); }