import React, { useEffect, useMemo, useRef, useState } from "react"; import { Activity, Apple, BadgeCheck, Bell, Calendar, CheckCircle2, ChevronRight, ClipboardList, CreditCard, Dumbbell, FileText, Flame, Home, LineChart, MessageSquare, Plus, Scale, Search, Settings, ShoppingBag, Sparkles, Target, Timer, TrendingUp, User, Utensils, X, } from "lucide-react"; // shadcn/ui import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Progress } from "@/components/ui/progress"; import { Separator } from "@/components/ui/separator"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, } from "@/components/ui/dialog"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Switch } from "@/components/ui/switch"; import { Textarea } from "@/components/ui/textarea"; /** * Evolve Fitness — Client-facing prototype * Palette: * White #FFFFFF * Obsidian #0F1C2E * Red #D31422 */ const BRAND = { white: "#FFFFFF", obsidian: "#0F1C2E", red: "#D31422", }; // Inline logo as data URL (attached primary logo) const LOGO_DATA_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAIAAADwf7zUAACsfGNhQlgAAKx8anVtYgAAAB5qdW1kYzJwAAAAAGhtZGFwAAAAAHhtZGNvAAAAAHhtZHNwAAAAAHhtZHRwAAAAAHhtZGVuAAAAAHhtZGlrAAAAAHhtZGlkAAAAAHhtZHF0AAAAAHhtZHRyAAAAAHhtZHB0AAAAAHhtZHRsAAAAAHhtZHRhAAAAAHhtZHN0AAAAAHhtZHRvAAAAAHhtZHRzAAAAAHhtZHN1AAAAAHhtZHR1AAAAAHhtZHVkAAAAAHhtZHVpAAAAAHhtZHViAAAAAHhtZHVhAAAAAHhtZHViAAAAAHhtZHVjAAAAAHhtZHVkAAAAAHhtZHVlAAAAAHhtZHVmAAAAAHhtZHVnAAAAAHhtZHVhAAAAAHhtZHVpAAAAAHhtZHVqAAAAAHhtZHVrAAAAAHhtZHVsAAAAAHhtZHVtAAAAAHhtZHVuAAAAAHhtZHVvAAAAAHhtZHVwAAAAAHhtZHVxAAAAAHhtZHVyAAAAAHhtZHVzAAAAAHhtZHV0AAAAAHhtZHV1AAAAAHhtZHV2AAAAAHhtZHV3AAAAAHhtZHV4AAAAAHhtZHV5AAAAAHhtZHV6AAAAAHhtZHV7AAAAAHhtZHV8AAAAAHhtZHV9AAAAAHhtZHV+AAAAAHhtZHUA" + ""; // NOTE: The logo base64 is intentionally truncated in this preview stub. // If you need the full embedded logo (exact file), tell me and I’ll paste the complete data URL. function cn(...classes) { return classes.filter(Boolean).join(" "); } function useInterval(callback, delay) { const savedRef = useRef(callback); useEffect(() => { savedRef.current = callback; }, [callback]); useEffect(() => { if (delay == null) return; const id = setInterval(() => savedRef.current(), delay); return () => clearInterval(id); }, [delay]); } const NAV = [ { key: "home", label: "Home", icon: Home }, { key: "workouts", label: "Workouts", icon: Dumbbell }, { key: "habits", label: "Habits", icon: Target }, { key: "nutrition", label: "Nutrition", icon: Utensils }, { key: "metrics", label: "Measurements", icon: LineChart }, { key: "forms", label: "Forms", icon: FileText }, { key: "shop", label: "Packages", icon: ShoppingBag }, { key: "messages", label: "Messages", icon: MessageSquare }, ]; const PROGRAMS = [ { id: "1on1", name: "1:1 Coaching", desc: "Individual plan, weekly check-ins, and training guidance.", badge: "Personal", icon: BadgeCheck, }, { id: "group", name: "Group Training", desc: "Class schedule, team challenges, and community accountability.", badge: "Community", icon: UsersIcon, }, { id: "rise", name: "RiSE", desc: "Cancer-informed training, fatigue-aware progressions, and support.", badge: "Specialized", icon: Sparkles, }, ]; const SAMPLE_ROUTINES = [ { id: "r1", name: "Upper A (Strength)", tags: ["Push", "Pull"], exercises: [ { name: "Incline DB Press", sets: [{ reps: 8, weight: 60 }, { reps: 8, weight: 60 }, { reps: 8, weight: 60 }] }, { name: "Chest-Supported Row", sets: [{ reps: 10, weight: 80 }, { reps: 10, weight: 80 }, { reps: 10, weight: 80 }] }, { name: "DB Shoulder Press", sets: [{ reps: 10, weight: 45 }, { reps: 10, weight: 45 }] }, { name: "Cable Face Pull", sets: [{ reps: 15, weight: 35 }, { reps: 15, weight: 35 }] }, ], }, { id: "r2", name: "Lower A (Strength)", tags: ["Squat", "Hinge"], exercises: [ { name: "Goblet Squat", sets: [{ reps: 10, weight: 70 }, { reps: 10, weight: 70 }, { reps: 10, weight: 70 }] }, { name: "RDL", sets: [{ reps: 8, weight: 135 }, { reps: 8, weight: 135 }, { reps: 8, weight: 135 }] }, { name: "Split Squat", sets: [{ reps: 10, weight: 40 }, { reps: 10, weight: 40 }] }, { name: "Calf Raise", sets: [{ reps: 15, weight: 90 }, { reps: 15, weight: 90 }] }, ], }, ]; const DEFAULT_HABITS = [ { id: "h1", label: "Protein target", icon: Flame, goal: "160g", streak: 4, checked: false }, { id: "h2", label: "Steps", icon: Activity, goal: "8,000", streak: 7, checked: true }, { id: "h3", label: "Water", icon: Apple, goal: "90 oz", streak: 2, checked: false }, { id: "h4", label: "Sleep", icon: Timer, goal: "7+ hrs", streak: 5, checked: true }, ]; const PACKAGE_CATALOG = [ { id: "p1", name: "5 Sessions", price: 249, desc: "Great for a reset and technique cleanup.", includes: ["5 training sessions", "Program tweaks", "Messaging support"], }, { id: "p2", name: "10 Sessions", price: 449, desc: "Best value for building momentum.", includes: ["10 training sessions", "Monthly assessment", "Habit targets"], featured: true, }, { id: "p3", name: "RiSE Starter", price: 299, desc: "Cancer-informed onboarding + 4 coached sessions.", includes: ["Intake & screening", "4 sessions", "Fatigue-aware plan"], }, ]; function UsersIcon(props) { return ( ); } function AppShell({ active, setActive, children }) { return (
{children}
); } function TopBar({ onNavigate }) { return (
{/* Falls back to brand mark if embedded logo is truncated */} Evolve Fitness { e.currentTarget.style.display = "none"; }} />
Evolve Fitness
Client App (Prototype)
Notifications
Coach check-in ready Tap Forms → Weekly Check-In
New routine assigned Workouts → Upper A (Strength)
); } function SideNav({ active, setActive }) { return (
NAVIGATION
Client
{NAV.map((item) => { const Icon = item.icon; const isActive = active === item.key; return ( ); })}
PROGRAM
{PROGRAMS.map((p) => { const Icon = p.icon; return (
{p.name}
{p.desc}
{p.badge}
); })}
); } function MobileNav({ active, setActive }) { return (
{NAV.slice(0, 8).map((item) => { const Icon = item.icon; const isActive = active === item.key; return ( ); })}
); } function HomeView({ habits, onToggleHabit, onStartWorkout }) { const checked = habits.filter((h) => h.checked).length; const pct = Math.round((checked / Math.max(habits.length, 1)) * 100); return (
Today
Build momentum, not perfection.
Your plan is built to be simple, trackable, and sustainable. Log the work, hit your anchors, and check in weekly.
Assigned: Upper A (Strength) Next check-in: Sunday
Daily Habits
Completion
{pct}%
{habits.slice(0, 4).map((h) => { const Icon = h.icon; return (
{h.label}
Goal: {h.goal} • Streak: {h.streak} days
onToggleHabit(h.id)} />
); })}
Progress Snapshot
Coach Notes
Weekly
Keep reps smooth and leave 1–2 in the tank this week. Aim for a short walk after dinner on non-training days.
Upcoming
); } function MetricTile({ label, value, unit, icon: Icon }) { return (
{label}
{value} {unit}
); } function UpcomingTile({ title, subtitle, icon: Icon }) { return (
{title}
{subtitle}
); } function WorkoutsView({ routines, onStartFromRoutine }) { const [query, setQuery] = useState(""); const filtered = useMemo(() => { const q = query.trim().toLowerCase(); if (!q) return routines; return routines.filter((r) => r.name.toLowerCase().includes(q) || r.tags.join(" ").toLowerCase().includes(q)); }, [query, routines]); return (
Workouts
Hevy-style logging: exercises, sets, reps, and weight.
setQuery(e.target.value)} />
{filtered.map((r) => (
{r.name} Assigned
{r.tags.map((t) => ( {t} ))}
{r.exercises.slice(0, 3).map((ex) => (
{ex.name}
{ex.sets.length} sets
))} {r.exercises.length > 3 && (
+ {r.exercises.length - 3} more
)}
))}
Recent Logs
{["Upper A (Strength)", "Walk + Mobility", "Lower A (Strength)"].map((t, idx) => (
{t}
{idx === 0 ? "Yesterday" : idx === 1 ? "2 days ago" : "Last week"}
{idx === 1 ? "Recovery" : "Strength"}
))}
); } function WorkoutSession({ open, onOpenChange, routine }) { const [notes, setNotes] = useState(""); const [timerOn, setTimerOn] = useState(false); const [seconds, setSeconds] = useState(0); useEffect(() => { if (open) { setNotes(""); setTimerOn(false); setSeconds(0); } }, [open]); useInterval( () => { setSeconds((s) => s + 1); }, timerOn ? 1000 : null ); const mm = String(Math.floor(seconds / 60)).padStart(2, "0"); const ss = String(seconds % 60).padStart(2, "0"); return ( {routine?.name || "Workout"}
{mm}:{ss}
Log sets like Hevy: adjust reps/weight per set, add sets, and leave notes.
{routine?.exercises?.map((ex) => ( {ex.name}
{ex.sets.map((s, idx) => (
Set {idx + 1}
))}
))} Session Notes
); } function HabitsView({ habits, onToggleHabit }) { return (
Habits
Daily anchors your coach can assign and track.
Today’s Habits
{habits.map((h) => { const Icon = h.icon; return (
{h.label}
Goal: {h.goal} • Streak: {h.streak} days
onToggleHabit(h.id)} />
); })}
Coach-Assigned Targets
); } function TargetTile({ title, value, note }) { return (
{title}
{value}
{note}
); } function NutritionView() { const [calories, setCalories] = useState(1950); const [protein, setProtein] = useState(148); const [carbs, setCarbs] = useState(170); const [fat, setFat] = useState(62); const kcalPct = Math.min(100, Math.round((calories / 2200) * 100)); const pPct = Math.min(100, Math.round((protein / 160) * 100)); return (
Nutrition
Simple tracking (with room for deeper integrations later).
Today’s Summary
Coach Focus
This Week’s Priority
Hit protein first, then calories.
Quick Inputs (demo)
setCalories(Number(e.target.value || 0))} /> setProtein(Number(e.target.value || 0))} /> setCarbs(Number(e.target.value || 0))} /> setFat(Number(e.target.value || 0))} />
Calories • Protein • Carbs • Fat
); } function MacroRow({ label, value, pct, highlight }) { return (
{label}
{value}
); } function TipRow({ text }) { return (
{text}
); } function MeasurementsView() { return (
Measurements
Track body metrics, photos, and trends.
Quick Add
History
{[ { date: "Jan 2", w: "284", waist: "44.5" }, { date: "Dec 26", w: "286", waist: "45.0" }, { date: "Dec 19", w: "287", waist: "45.4" }, ].map((r) => (
{r.date}
Weight {r.w} • Waist {r.waist}
))}
Photos
Upload progress photos (front/side/back) and keep them private.
); } function FormsView() { return (
Forms
Intake, waivers, contracts, and weekly check-ins.
Weekly Check-In Intake Waiver Weekly Check-In
Client Intake
Liability Waiver (Preview)
This is a placeholder waiver/contract module. In production, this would support:
  • Templates per program (1:1, Group, RiSE)
  • E-signature + timestamp
  • PDF storage in client profile
  • Renewal prompts
); } function ShopView({ onPurchase }) { return (
Training Packages
In-app purchase flow (Stripe/Apple Pay in production).
{PACKAGE_CATALOG.map((p) => (
{p.name} {p.featured && ( Best Value )}
{p.desc}
${p.price}
{p.includes.map((i) => (
{i}
))}
))}
What happens after purchase?
); } function StepTile({ title, desc }) { return (
{title}
{desc}
); } function MessagesView() { return (
Messages
Simple coach-client messaging (chat + file share later).
Threads
{[ { name: "Coach Brad", note: "How did the presses feel?" }, { name: "Group: RUSH", note: "Thursday class is on." }, { name: "RiSE Support", note: "Reminder: fatigue scale 1–10" }, ].map((t) => ( ))}
Coach Brad
); } function Bubble({ side, text }) { const isRight = side === "right"; return (
{text}
); } function PurchaseDialog({ open, onOpenChange, pkg }) { return ( Checkout Demo purchase flow. Production would integrate Stripe + Apple Pay/Google Pay.
{pkg?.name || "Package"}
Evolve Fitness
${pkg?.price ?? "—"}
); } export default function EvolveFitnessClientApp() { const [active, setActive] = useState("home"); const [habits, setHabits] = useState(DEFAULT_HABITS); const [routines] = useState(SAMPLE_ROUTINES); const [workoutOpen, setWorkoutOpen] = useState(false); const [workoutRoutine, setWorkoutRoutine] = useState(null); const [checkoutOpen, setCheckoutOpen] = useState(false); const [checkoutPkg, setCheckoutPkg] = useState(null); function toggleHabit(id) { setHabits((prev) => prev.map((h) => (h.id === id ? { ...h, checked: !h.checked } : h))); } function startWorkoutFromRoutine(r) { setWorkoutRoutine(r); setWorkoutOpen(true); } function startAssignedWorkout() { startWorkoutFromRoutine(routines[0]); } function purchase(pkg) { setCheckoutPkg(pkg); setCheckoutOpen(true); } const view = (() => { switch (active) { case "home": return ; case "workouts": return ; case "habits": return ; case "nutrition": return ; case "metrics": return ; case "forms": return ; case "shop": return ; case "messages": return ; default: return ; } })(); return ( <> {view} {/* Minimal brand footer */}
Prototype UI — client-facing
Next: CRM/Admin view
> ); }