diff --git a/AGENTS.md b/AGENTS.md index 256e0c2..11c7ac1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1537,6 +1537,14 @@ session with **no other memory of this project**. So: auto-opened welcome modal. ⚠️ `SignupDialog` is a **default-only** export, so lazy-load it as `lazy(() => import('…/SignupDialog'))`. + - **Pass the app on — Android only (2026-10-26):** the About page renders + `ShareAppCard` when `getPlatform() === 'android'` (APK/Zapstore; hidden on + web/iOS): a **QR of the Zapstore listing** (`APP_INSTALL_URL` in + `lib/platform.ts`, single-sourced), a **share-sheet** button (Nearby + Share/SMS/etc.), and `NfcWriteButton` to write the install URL to an NFC tag. + ⚠️ Deliberately **no peer-to-peer APK transfer** — that needs native Wi‑Fi + Direct/BLE + a `PackageInstaller` flow and real-device QA; Zapstore handles + installs/updates. (Not visually verified on-device yet.) - **First-run checklist + backup-reminder gating (fixed 2026-10-12).** Two onboarding prompts nagged returning users: 1. `FirstRunChecklist` (map) showed for **any logged-in user** until they diff --git a/src/components/ShareAppCard.tsx b/src/components/ShareAppCard.tsx new file mode 100644 index 0000000..314b429 --- /dev/null +++ b/src/components/ShareAppCard.tsx @@ -0,0 +1,78 @@ +import { useState } from 'react'; +import { Check, Share2 } from 'lucide-react'; +import { Card, CardContent } from '@/components/ui/card'; +import { Button } from '@/components/ui/button'; +import { QRCodeCanvas } from '@/components/ui/qrcode'; +import { NfcWriteButton } from '@/components/NfcWriteButton'; +import { useTranslation } from '@/contexts/language'; +import { useToast } from '@/hooks/useToast'; +import { APP_INSTALL_URL, getPlatform } from '@/lib/platform'; + +/** + * "Pass the app on" — Android only (APK / Zapstore). + * + * The QR carries the **Zapstore listing** for this app; scanning it on another + * Android phone opens the store page and installs/updates via Zapstore. The + * share button hands the same link to Android's share sheet (Nearby Share, + * Bluetooth, messages…), and — where the device supports NFC writing — the link + * can be written to a tag for a genuine tap-to-open handoff. + * + * We deliberately do NOT move APK bytes peer-to-peer: that needs native + * Wi‑Fi Direct/BLE + a PackageInstaller flow and real-device QA, and Zapstore + * already handles installs/updates. Renders nothing off Android (iOS can't + * sideload; desktop has no use for it). + */ +export function ShareAppCard() { + const { t } = useTranslation(); + const { toast } = useToast(); + const [copied, setCopied] = useState(false); + + if (getPlatform() !== 'android') return null; + + const share = async () => { + try { + if (navigator.share) { + await navigator.share({ + title: 'SkateSpots', + text: t('settingsUi.about.downloadAppDesc'), + url: APP_INSTALL_URL, + }); + return; + } + await navigator.clipboard.writeText(APP_INSTALL_URL); + setCopied(true); + toast({ title: t('common.copied'), description: APP_INSTALL_URL }); + window.setTimeout(() => setCopied(false), 1600); + } catch { + // Share sheet cancelled — nothing to report. + } + }; + + return ( + + +
+

+ {t('common.share')} SkateSpots +

+

{t('settingsUi.about.downloadAppDesc')}

+
+ +
+ +
+ + + + {/* Tap-to-open: write the install link to an NFC tag (no-op where unsupported). */} + +
+
+ ); +} diff --git a/src/lib/platform.ts b/src/lib/platform.ts index fe5afb3..8b28650 100644 --- a/src/lib/platform.ts +++ b/src/lib/platform.ts @@ -27,6 +27,9 @@ export function getPlatform(): string { } } +/** Canonical Zapstore listing for this app (install + updates). Android only. */ +export const APP_INSTALL_URL = 'https://zapstore.dev/apps/org.skatespots.app'; + /** * SkateSpots platform Lightning address. Receives Sasquatch Pro passes AND * marketplace listing fees — the same address, deliberately. Single source of diff --git a/src/pages/AboutPage.tsx b/src/pages/AboutPage.tsx index dd57ee9..7bde56e 100644 --- a/src/pages/AboutPage.tsx +++ b/src/pages/AboutPage.tsx @@ -2,6 +2,8 @@ import { useSeoMeta } from '@unhead/react'; import { Link } from 'react-router-dom'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; +import { ShareAppCard } from '@/components/ShareAppCard'; +import { APP_INSTALL_URL } from '@/lib/platform'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useToast } from '@/hooks/useToast'; import { @@ -233,7 +235,7 @@ Version: v0.1.0`;

+ {/* Pass the app on (Android only) — QR / share sheet / NFC tag. */} + + {/* Credits */}