From f4f897d0fde627f19a491666f2f2a792e86977d7 Mon Sep 17 00:00:00 2001 From: MP2EZ <182439403+MP2EZ@users.noreply.github.com> Date: Mon, 25 May 2026 17:25:24 -0700 Subject: [PATCH] feat(launch): repurpose /download as waitlist + expose main site in prod MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the last blockers to flipping the splash gate so production (main branch) serves the full site, which is needed for TestFlight + App Store review. The app isn't downloadable yet — but the previous /download page (placeholder app-store badges marked '(graphic needed)') would be embarrassing for users and confidence-breaking for App Store reviewers. Three coordinated changes: 1. Extract the splash page's waitlist signup form into components/shared/WaitlistSignupForm.tsx so both the splash and the new /download can use it. Splash refactored to consume it; visual no-change to the splash itself. 2. Rewrite /download as the pre-launch waitlist experience: - Hero: 'Coming soon to iOS and Android' (was 'Download Being') - Primary CTA: waitlist signup form - REMOVED: placeholder iOS/Android badges + QR codes - REMOVED: duplicate bottom 'Download for iOS / Android' CTA - REFRAMED: pricing + system requirements as 'What to expect when we launch' - FAQ retained with one new entry ('When will Being launch?') Every existing CTA across the site (5 of them on home/features/ philosophy) still routes to /download — they now land on a coherent waitlist signup instead of broken download buttons. 3. DesktopNav 'Download' link text → 'Get Early Access'. URL unchanged. 4. NEXT_PUBLIC_SHOW_FULL_SITE flipped to unconditional 'true' in deploy.yml. The splash component + redirect logic remain in the codebase as emergency-fallback, but the splash is now unreachable in deployed envs — / redirects to /home on both preview and main. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/deploy.yml | 6 +- app/(main)/download/page.tsx | 142 +++++++---------------- app/(standalone)/page.tsx | 111 +----------------- components/navigation/DesktopNav.tsx | 2 +- components/shared/WaitlistSignupForm.tsx | 96 +++++++++++++++ 5 files changed, 148 insertions(+), 209 deletions(-) create mode 100644 components/shared/WaitlistSignupForm.tsx diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d262281..88679b3 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -49,7 +49,11 @@ jobs: - name: Build with OpenNext run: npx opennextjs-cloudflare build env: - NEXT_PUBLIC_SHOW_FULL_SITE: ${{ github.ref_name == 'preview' && 'true' || 'false' }} + # Always serve the full site (both preview and main). The splash at / + # is now unreachable in deployed envs — it stays in the codebase as + # an emergency-fallback option but the runtime redirect carries + # / → /home. /download serves as the pre-launch waitlist page. + NEXT_PUBLIC_SHOW_FULL_SITE: 'true' - name: Deploy to Cloudflare Workers uses: cloudflare/wrangler-action@v3 diff --git a/app/(main)/download/page.tsx b/app/(main)/download/page.tsx index 7f03d74..2f62885 100644 --- a/app/(main)/download/page.tsx +++ b/app/(main)/download/page.tsx @@ -1,97 +1,47 @@ /** - * Download Page - App store links and pricing - * Professional SaaS Design - * NOTE: App store badges and QR codes need graphic assets - * NOTE: Pricing needs verification from product team + * Download Page — pre-launch state + * + * The app isn't in the stores yet. Every existing CTA across the site + * routes here, so this page serves as the waitlist signup until launch. + * When real app-store badges and downloads are available, the hero + + * waitlist form get replaced with badges + QR codes; the supporting + * content (pricing, system requirements, FAQ) stays as-is. */ import BrainIcon from '@/components/shared/BrainIcon'; -import Button from '@/components/shared/Button'; +import { WaitlistSignupForm } from '@/components/shared/WaitlistSignupForm'; + +export const metadata = { + title: 'Get Early Access | Being', + description: 'Join the waitlist to be the first to know when Being launches on iOS and Android.', +}; export default function DownloadPage() { return (
- {/* Hero Section */} -
-
+ {/* Hero + waitlist */} +
+

- Download Being + Coming soon to iOS and Android

-

- Start your Stoic Mindfulness practice today. 1 month free trial included. - No credit card required. +

+ Get early access + a free month trial when we launch. We’ll email you the + moment Being is in the App Store and Google Play.

+
- {/* App Store Badges */} + {/* What to expect when we launch — Pricing */}
-
-

- Available on iOS and Android -

- -
- {/* iOS App Store Badge - PLACEHOLDER */} -
-
-
🍎
-

iOS App Store Badge

-

(graphic needed)

-
-
- - {/* Google Play Badge - PLACEHOLDER */} -
-
-
🤖
-

Google Play Badge

-

(graphic needed)

-
-
-
- - {/* QR Codes - PLACEHOLDER */} -
-

- Scan to download on your phone -

-
-
-
-
-
📱
-

iOS QR Code

-

(graphic needed)

-
-
-

iPhone & iPad

-
- -
-
-
-
📱
-

Android QR Code

-

(graphic needed)

-
-
-

Android Devices

-
-
-
-
-
- - {/* Pricing */} -

- Simple, Transparent Pricing + What to expect when we launch

No hidden fees. No data selling. Just mindfulness practice with deeper meaning. @@ -114,7 +64,7 @@ export default function DownloadPage() {

  • - Daily check-ins & assessments + Daily check-ins & assessments
  • @@ -170,7 +120,7 @@ export default function DownloadPage() {
  • {/* System Requirements */} -
    +

    System Requirements @@ -181,7 +131,7 @@ export default function DownloadPage() {

    🍎 - iOS & iPadOS + iOS & iPadOS

    • @@ -241,19 +191,29 @@ export default function DownloadPage() {

    {/* FAQ */} -
    +

    - Download FAQ + Frequently asked questions

    +
    +

    + When will Being launch? +

    +

    + We’re finalizing app-store review now. Join the waitlist above and we’ll + email you as soon as Being is available to download. +

    +
    +

    Do I need to create an account?

    - No account required to start. Being works completely offline with local storage. + No account required to start. Being will work completely offline with local storage. You can optionally create an account later for cloud backup across devices.

    @@ -263,7 +223,7 @@ export default function DownloadPage() { What happens after my free trial ends?

    - Nothing automatically. We won't charge you unless you explicitly subscribe. You'll + Nothing automatically. We won’t charge you unless you explicitly subscribe. You’ll keep access to your data, but check-ins and assessments will be limited to view-only.

    @@ -297,33 +257,13 @@ export default function DownloadPage() { Can I cancel my subscription?

    - Yes, anytime. Cancel through your App Store or Google Play account settings. You'll + Yes, anytime. Cancel through your App Store or Google Play account settings. You’ll keep access until the end of your billing period, and you can always export your data.

    - - {/* Final CTA */} -
    -
    -

    - Ready to begin? -

    -

    - Join thousands practicing Stoic Mindfulness. Start your free trial today. -

    -
    - - -
    -
    -
    ); } diff --git a/app/(standalone)/page.tsx b/app/(standalone)/page.tsx index af3cdd8..921fae2 100644 --- a/app/(standalone)/page.tsx +++ b/app/(standalone)/page.tsx @@ -1,43 +1,13 @@ /** * Coming Soon Page - Being * Single-focus email capture interstitial - * Launch until app store availability + * Shown at / when NEXT_PUBLIC_SHOW_FULL_SITE !== 'true' (see layout) */ -'use client'; - -import { useState, FormEvent } from 'react'; import BrainIcon from '@/components/shared/BrainIcon'; +import { WaitlistSignupForm } from '@/components/shared/WaitlistSignupForm'; export default function ComingSoon() { - const [email, setEmail] = useState(''); - const [status, setStatus] = useState<'idle' | 'submitting' | 'success' | 'error'>('idle'); - const [errorMessage, setErrorMessage] = useState(''); - - const handleSubmit = async (e: FormEvent) => { - e.preventDefault(); - setStatus('submitting'); - setErrorMessage(''); - - try { - const response = await fetch('/api/waitlist', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email }), - }); - - if (!response.ok) { - throw new Error('Failed to join waitlist'); - } - - setStatus('success'); - setEmail(''); - } catch (error) { - setStatus('error'); - setErrorMessage('Something went wrong. Please try again.'); - } - }; - return (
    @@ -58,89 +28,18 @@ export default function ComingSoon() {
    -

    +

    Ancient Stoic wisdom meets modern mental health practice.

    -

    +

    Be the first to know when we launch.

    {/* Email Capture Form */} - {status === 'success' ? ( -
    -

    - You're on the list -

    -

    - We'll notify you as soon as Being launches on the App Store and Google Play. -

    -
    - ) : ( -
    -
    - - setEmail(e.target.value)} - placeholder="Enter your email" - required - disabled={status === 'submitting'} - className=" - flex-1 px-4 py-3 - rounded-large border-2 border-gray-300 - text-base text-gray-900 placeholder:text-gray-400 - focus:outline-none focus:ring-2 focus:ring-accent-500 focus:border-accent-500 - disabled:opacity-50 disabled:cursor-not-allowed - transition-all duration-150 - min-h-[48px] - " - /> - -
    - - {status === 'error' && ( -

    - {errorMessage} -

    - )} - -

    - We'll send you one email when Being launches. - No spam, ever. Unsubscribe anytime. -

    -
    - )} + {/* Trust Signals */}
    diff --git a/components/navigation/DesktopNav.tsx b/components/navigation/DesktopNav.tsx index a618bd5..a240209 100644 --- a/components/navigation/DesktopNav.tsx +++ b/components/navigation/DesktopNav.tsx @@ -29,7 +29,7 @@ export default function DesktopNav() { Features - Download + Get Early Access
    diff --git a/components/shared/WaitlistSignupForm.tsx b/components/shared/WaitlistSignupForm.tsx new file mode 100644 index 0000000..875ab3a --- /dev/null +++ b/components/shared/WaitlistSignupForm.tsx @@ -0,0 +1,96 @@ +'use client'; + +/** + * Waitlist signup form. + * + * Used on: + * - / (splash) when NEXT_PUBLIC_SHOW_FULL_SITE !== 'true' + * - /download (pre-launch state until the app is in the stores) + * + * POSTs to the existing /api/waitlist endpoint (Notion-backed). + * Self-contained: idle / submitting / success / error states are + * managed internally. + */ + +import { useState, FormEvent } from 'react'; + +export function WaitlistSignupForm() { + const [email, setEmail] = useState(''); + const [status, setStatus] = useState<'idle' | 'submitting' | 'success' | 'error'>('idle'); + const [errorMessage, setErrorMessage] = useState(''); + + const handleSubmit = async (e: FormEvent) => { + e.preventDefault(); + setStatus('submitting'); + setErrorMessage(''); + + try { + const response = await fetch('/api/waitlist', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email }), + }); + + if (!response.ok) { + throw new Error('Failed to join waitlist'); + } + + setStatus('success'); + setEmail(''); + } catch { + setStatus('error'); + setErrorMessage('Something went wrong. Please try again.'); + } + }; + + if (status === 'success') { + return ( +
    +

    + You're on the list +

    +

    + We'll notify you as soon as Being launches on the App Store and Google Play. +

    +
    + ); + } + + return ( +
    +
    + + setEmail(e.target.value)} + placeholder="Enter your email" + required + disabled={status === 'submitting'} + className="flex-1 px-4 py-3 rounded-large border-2 border-gray-300 text-base text-gray-900 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-accent-500 focus:border-accent-500 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-150 min-h-[48px]" + /> + +
    + + {status === 'error' && ( +

    + {errorMessage} +

    + )} + +

    + We'll send you one email when Being launches. + No spam, ever. Unsubscribe anytime. +

    +
    + ); +}