Intake Forms

Patient onboarding forms for GLP-1, NAD+, and Microdose products.

Overview

YourEra operates three separate React SPA intake forms, each tailored to a specific product line. All three are hosted on CloudFront/S3 at intake.hisera.com with product-specific paths.

Deployment

ProductPathSteps
GLP-1 Weightloss /start-online-visit/glp-1/ 19
NAD+ Wellness /start-online-visit/nad/ 23
Microdose /start-online-visit/micro/ 22

Infrastructure

ComponentValue
S3 Bucket hisera-static-assets/intake/start-online-visit/
CloudFront E2MF26IKHV4PLZ (d3stenc5l9iicr.cloudfront.net)
API intake-api.hisera.com (Intake Gateway)
Deploy scripts/deploy-intakes.sh --deploy (tests, build, S3 sync, CF invalidation)
DNS Warning intake.yourera.com points to Vercel/Bask (CNAME cname.vercel-dns.com) — NEVER TOUCH this record. intake.hisera.com points to CloudFront.

Architecture (Per Intake)

┌───────────────────────────────────────┐
│  intake.hisera.com (CloudFront + S3)  │
│  React SPA (Vite)                     │
└────────────┬──────────────────────────┘
             
┌────────────▼──────────────────────────┐
│  intake-api.hisera.com (ECS)          │
│  Intake Gateway                       │
├───────────┬───────────┬───────────────┤
│  Stripe   │  Canvas   │  Google       │
│  Payment  │  Patient  │  Places       │
│  API      │  Creation │  Autocomplete │
└───────────┴───────────┴───────────────┘

GLP-1 Weightloss

The GLP-1 intake is the primary product intake with 19 steps. It collects patient demographics, medical history, body metrics, and payment information for Semaglutide and Tirzepatide prescriptions.

Step Flow (19 Steps)

#StepDescription
1GoalWeight loss goal selection
2AccountEmail + password (Google OAuth or email OTP)
3DOBDate of birth (auto-formatted MM-DD-YYYY)
4SexBiological sex at birth
5PhonePhone number (auto-formatted)
6MedicationsCurrent GLP-1 or related medications
7MetricsHeight and weight for BMI calculation
8AddressShipping address with Google Places autocomplete
9CheckoutPlan selection and Stripe payment
10-17Medical QuestionsHealth history, allergies, conditions, pregnancy, thyroid
18ID UploadGovernment ID scan (barcode or OCR)
19DoneConfirmation and scheduling prompt

NAD+ Wellness

The NAD+ intake is a 23-step form for the NAD+ 200 mg/mL subcutaneous injection wellness protocol. It includes unique screening steps for G6PD deficiency, CKD, and cancer treatment history that are not present in the other intakes.

Unique Steps

Product Details

FieldValue
Product NAD+ 200 mg/mL for Subcutaneous Injection, 5 mL Vial
Supplier Galleria (GMP)
Boothwyn SKU 12832
Program 12-week protocol
Price $170/month

Microdose

The Microdose intake is a 22-step form with unique medication preference selection and a diabetes medications disqualifier step.

Unique Steps

Shared Steps

The remaining steps follow the same pattern as the GLP-1 intake: account creation, demographics (DOB, sex, phone), address with autocomplete, payment checkout, medical history questions, ID upload, and confirmation.

Payment

All three intakes use Stripe for payment processing. The checkout step uses Stripe's PaymentElement (embedded, not redirect) to collect card details and create a SetupIntent that saves the card for future charges.

Payment Flow

  1. Intake frontend requests a SetupIntent from the Intake Gateway
  2. Stripe PaymentElement renders in-page for card collection
  3. Patient enters card details and confirms
  4. Card is saved as a Stripe PaymentMethod attached to the customer
  5. PaymentMethod ID is stored in the Integration Service payment_holds table
  6. Card is charged later when the prescription is approved (via orchestrator)
No Authorization Hold YourEra uses SetupIntent (save card) + off-session PaymentIntent (charge later), NOT authorization holds. The card is not charged at intake time.

Discount Codes

Patients can enter a discount code during checkout. The code is validated against Stripe coupons via the POST /validate-coupon endpoint on the Intake Gateway. The coupon ID in Stripe must match the code the patient enters.

Authentication

The intake forms support two authentication methods for the account creation step. The deployed (production) version and development version use different providers.

Production (Deploy Repo)

Development (Dev Repo)

Two Repos The dev repo (yourera-ios-app/react-intakes/) and deploy repo (yourEra-intake/) have significantly diverged. The deploy repo uses encryptAndStore/retrieveAndDecrypt (AES-256-GCM), GoogleSignIn, GTM, and ALLOWED_STATES. Always port changes manually between repos.

Draft Persistence

All intake forms implement client-side draft persistence using localStorage. Patient progress is saved automatically as they fill out the form, so they can resume later if they close the browser.

Implementation

Debounce Utility

// utils/debounce.js
export function createDebouncedFn(fn, ms) {
  let timer;
  const debouncedFn = (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), ms);
  };
  const cancelFn = () => clearTimeout(timer);
  return [debouncedFn, cancelFn];
}

ID Verification

The ID upload step supports multiple methods for capturing and verifying government-issued identification. The system attempts barcode scanning first, falls back to OCR, and allows manual upload as a last resort.

Verification Methods

  1. PDF417 Barcode Scan — Uses zxing-wasm to scan the PDF417 barcode on the back of US driver's licenses. This is the fastest and most accurate method.
  2. OCR Fallback — If barcode scanning fails, tesseract-wasm performs optical character recognition on the ID image to extract text fields.
  3. Manual Upload — If both automated methods fail, the patient can manually upload a photo of their ID. OCR is attempted on the uploaded image.

Extracted Fields

FieldSourceUsage
firstName Barcode / OCR Cross-referenced with intake name
lastName Barcode / OCR Cross-referenced with intake name
dateOfBirth Barcode / OCR Cross-referenced with intake DOB
address Barcode / OCR Cross-referenced with shipping address
expirationDate Barcode / OCR Validated to ensure ID is not expired
Camera Access The barcode scanner requires camera access. The app must have NSCameraUsageDescription in Info.plist (iOS) or camera permissions (web). Camera uses imperative UIKit presentation via CameraManager on iOS.