You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds a public /download landing page that walks users through installing DataTrak as a PWA, with platform-appropriate install flows.
Changes:
New route /download rendering DownloadPage — a responsive layout with install CTA + help text on mobile, and a QR code + desktop mockup on larger screens. The page is unauthenticated so users can reach it before signing in.
User menu entry "Download desktop app" in MenuList, hidden on mobile devices.
PWA install plumbing:
PwaInstallPromptProvider (hooks/usePwaInstallPrompt.tsx) captures Chromium's beforeinstallprompt event and exposes canPromptInstall / promptInstall() so the mobile install CTA can fire the native install dialog on Android Chrome/Edge. Also listens for appinstalled and infers an initial installed-state from display-mode matchMedia.
react-ios-pwa-prompt library (new dep) renders an iOS-styled "Add to Home Screen" overlay for Safari users, triggered manually via isShown. Custom copy passed for title / description / share & add-to-home-screen steps.
Click routing in MobileSection: native prompt if available → iOS overlay if on iOS → Android Chrome fallback text otherwise.
isIosDevice() helper added to utils/detectDevice.ts alongside the existing isAndroidDevice().
New icons: AndroidIcon, AppleIcon SVG components.
New assets: desktop/mobile background images and mockup screenshots in public/images/.
isAppInstalled is initialised with useState(isWebApp), which lazily calls isWebApp() once at mount. This works, but the value is never re-checked: if the user installs the app via a mechanism other...
isIosDevice() uses /iPhone|iPad|iPod/i but iPads running iOS 13+ switched to a desktop user-agent string ('Macintosh, Intel Mac OS X') by default in Safari. This means modern iPads return false her...
When canInstall is false (e.g., on Android in Firefox, or after the beforeinstallprompt event was already dismissed), onClick is set to undefined so the button silently does nothing while still app...
Local fix prompt (copy to your coding agent)
Fix these issues identified on the pull request. One commit per issue fixed.
packages/datatrak-web/src/views/DownloadPage/DownloadPage.tsx:223: handleInstallClick calls promptInstall() without awaiting it and without disabling the button first. Because promptInstall is async (it awaits deferredPrompt.prompt()), the button remains clickable while the native install dialog is open. A second click before setDeferredPrompt(null) runs will capture the same deferredPrompt from the closure (the state hasn't updated yet) and call .prompt() a second time on an already-consumed BeforeInstallPromptEvent. Fix: set a local 'prompting' state to true before calling and reset it after, or disable the button while the async operation is in flight.
The menu item for the download page uses externalIcon but ROUTES.DOWNLOAD is an internal route (/download). Using the external-link icon for internal navigation is a semantic mismatch that wi...
isIosDevice() misses iPadOS 13+. Since iPadOS 13, Safari on iPad sends 'Macintosh' in the user-agent rather than 'iPad', so /iPhone|iPad|iPod/i.test(navigator.userAgent) returns false on modern iPa...
getDownloadUrl wraps a value that never changes during a session (window.location.origin is stable in a SPA) into a needless function. Define it as a module-level constant instead: `const DOWNL...
The $visibility prop + visibilityCss helper is threaded through four styled components (RightColumn, Section, MockupImage, and implicitly MobileSection/QRCodeSection) to express a simple show/h...
MobileSection and QRCodeSection both render on every device and are shown/hidden purely via CSS breakpoints. MobileSection contains live state (showIosPrompt), a PWAPrompt DOM subtree, and calls us...
SectionLabel is an empty styled-component wrapper around Typography with no added styles or semantics. It adds indirection for no benefit — use Typography directly at the call site.
Local fix prompt (copy to your coding agent)
Fix these issues identified on the pull request. One commit per issue fixed.
packages/datatrak-web/src/hooks/usePwaInstallPrompt.tsx:57: If deferredPrompt.prompt() rejects (the spec allows this if the prompt was already consumed or the call is out of context), setDeferredPrompt(null) on line 58 is skipped. The stale deferred prompt stays in state, so canPromptInstall remains true and the install button keeps appearing — but every subsequent click will throw again. Wrap in try/finally: try { const result = await deferredPrompt.prompt(); return result.outcome; } finally { setDeferredPrompt(null); }
packages/datatrak-web/src/views/DownloadPage/DownloadPage.tsx:222: DownloadButton renders with onClick={undefined} but no disabled prop when canInstall is false (e.g. an Android user on Firefox/Samsung Browser where beforeinstallprompt never fires). The button looks interactive but is completely inert — tapping gives no feedback. At minimum add disabled={!canInstall} so the element is semantically inactive; or hide the button and only show the help text in that case.
packages/datatrak-web/src/views/DownloadPage/DownloadPage.tsx:152: SectionLabel is an empty styled-component wrapper around Typography with no added styles or semantics. It adds indirection for no benefit — use Typography directly at the call site.
packages/datatrak-web/src/hooks/usePwaInstallPrompt.tsx:36: useState(isWebApp) uses isWebApp as a lazy initialiser where isWebApp() returns true when running as a PWA (standalone/fullscreen/minimal-ui). While the logic is correct, isWebApp communicates 'is this running as a non-browser PWA', not 'is the app installed'. The inverted-sounding name will mislead future readers who expect isWebApp to mean 'is this a web browser session'. Consider extracting a clearly-named helper, e.g. isInstalledPwa(), that wraps the same matchMedia checks.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RN-1549 DataTrak downloads page
Adds a public
/downloadlanding page that walks users through installing DataTrak as a PWA, with platform-appropriate install flows.Changes:
/downloadrenderingDownloadPage— a responsive layout with install CTA + help text on mobile, and a QR code + desktop mockup on larger screens. The page is unauthenticated so users can reach it before signing in.MenuList, hidden on mobile devices.PwaInstallPromptProvider(hooks/usePwaInstallPrompt.tsx) captures Chromium'sbeforeinstallpromptevent and exposescanPromptInstall/promptInstall()so the mobile install CTA can fire the native install dialog on Android Chrome/Edge. Also listens forappinstalledand infers an initial installed-state fromdisplay-modematchMedia.react-ios-pwa-promptlibrary (new dep) renders an iOS-styled "Add to Home Screen" overlay for Safari users, triggered manually viaisShown. Custom copy passed for title / description / share & add-to-home-screen steps.MobileSection: native prompt if available → iOS overlay if on iOS → Android Chrome fallback text otherwise.isIosDevice()helper added toutils/detectDevice.tsalongside the existingisAndroidDevice().AndroidIcon,AppleIconSVG components.public/images/.Screenshots:
🦸 Review Hero