'use client'; import { LuCheck, LuChartLine, LuX } from 'react-icons/lu'; import ModalPortal from '@/components/ModalPortal'; import { useEnv } from '@/context/EnvContext'; import { useTranslation } from '@/hooks/useTranslation'; import { useSettingsStore } from '@/store/settingsStore'; import { optInTelemetry, optOutTelemetry } from '@/utils/telemetry'; interface TelemetryConsentDialogProps { open: boolean; onClose: () => void; } /** * First-launch consent prompt asking new users whether to share anonymous * usage data. Shown to a small fraction of new users; the rest are opted out * silently. */ export default function TelemetryConsentDialog({ open, onClose }: TelemetryConsentDialogProps) { const _ = useTranslation(); const { envConfig } = useEnv(); if (!open) return null; // Persist `telemetryEnabled` via the settings store if it has already // been seeded by the library/reader page; otherwise go straight through // appService.loadSettings + saveSettings so we don't overwrite the on-disk // file with a near-empty store snapshot. const persistTelemetryEnabled = async (value: boolean) => { const store = useSettingsStore.getState(); if (store.settings && typeof store.settings.version === 'number') { const next = { ...store.settings, telemetryEnabled: value }; store.setSettings(next); await store.saveSettings(envConfig, next); } else { const appService = await envConfig.getAppService(); const settings = await appService.loadSettings(); settings.telemetryEnabled = value; await appService.saveSettings(settings); } }; const accept = async () => { optInTelemetry(); await persistTelemetryEnabled(true); onClose(); }; const decline = async () => { optOutTelemetry(); await persistTelemetryEnabled(false); onClose(); }; return (

{_('Help improve Readest')}

{_( 'Share anonymous usage data so we can understand how Readest is used and make it better.', )}

{_('You can change this anytime in Settings.')}

); } function ConsentRow({ kind, label }: { kind: 'positive' | 'negative'; label: string }) { const isPositive = kind === 'positive'; // Positive: filled disc. We deliberately skip `eink-bordered` here so the // eink override that paints `bg-base-content` solid wins, keeping the row // visually distinct from the negative (outlined) rows on e-paper. // Negative: outlined disc — `eink-bordered` flips to base-100 + 1px border // under eink, and `border-base-content/15` carries the boundary on color // themes. return (
  • {label}
  • ); }