import streamlit as st from auth_token import login, initiate_signup, complete_signup, STARTUP_WARNINGS # Show critical startup warnings (missing API keys etc.) if STARTUP_WARNINGS and not __import__('streamlit').session_state.get('_warnings_shown'): for _w in STARTUP_WARNINGS: __import__('streamlit').session_state['_startup_warning'] = _w __import__('streamlit').session_state['_warnings_shown'] = True import streamlit.components.v1 as components import os st.set_page_config(page_title="FitPlan Pro", page_icon="⚡", layout="wide") # ── Already logged in → go to profile ──────────────────────────────────────── if st.session_state.get("logged_in"): # Always go through profile which loads from DB and routes correctly st.switch_page("pages/1_Profile.py") # ── State init ──────────────────────────────────────────────────────────────── for k, v in [("page_mode","landing"),("signup_step","form"),("pending_signup",{})]: if k not in st.session_state: st.session_state[k] = v # ── Hide Streamlit chrome, make iframe full screen ─────────────────────────── st.markdown(""" """, unsafe_allow_html=True) # ══════════════════════════════════════════════════════════════════════════════ # ACTION HANDLERS (query params set by JS window.location.href inside iframe) # ══════════════════════════════════════════════════════════════════════════════ params = st.query_params action = params.get("action", "") # ── STEP 5: LOGIN ───────────────────────────────────────────────────────────── if action == "login": u = params.get("u", ""); p = params.get("p", "") if u and p: ok, token, real_username, msg = login(u, p) if ok: st.session_state.logged_in = True st.session_state.username = real_username st.session_state.auth_token = token st.query_params.clear() # ── Load profile + plan from DB immediately on login ────────────── _db_err = None try: import traceback as _tb from utils.db import get_user_profile, get_active_plan # Load profile from DB prof = get_user_profile(real_username) if prof: st.session_state.user_data = prof # Load active plan from DB existing = get_active_plan(real_username) if existing and existing.get("days") and len(existing["days"]) > 0: structured = [] for d in existing["days"]: # workout_json is already parsed by get_active_plan structured.append({ "day": int(d.get("day_number", 1)), "is_rest_day": bool(d.get("is_rest_day", False)), "muscle_group": str(d.get("muscle_group") or "Full Body"), "workout": d.get("workout_json") or [], "dietary": d.get("dietary_json") or {}, "pre_stretch": d.get("pre_stretch_json") or [], "post_stretch": d.get("post_stretch_json") or [], }) structured.sort(key=lambda x: x["day"]) st.session_state.structured_days = structured st.session_state.full_plan_data = structured st.session_state.dietary_type = existing.get("dietary_type", "veg") st.session_state.plan_id = existing.get("plan_id", "") st.session_state.plan_start = existing.get("created_at_date", "") st.session_state.plan_duration = len(structured) st.session_state.workout_plan = "\n".join([ f"## Day {d['day']} - {d['muscle_group']}" for d in structured ]) st.session_state._plan_checked = True st.session_state._db_loaded_dash = True # Plan ready — go straight to dashboard st.switch_page("pages/2_Dashboard.py") except Exception as _e: _db_err = str(_e) import traceback; traceback.print_exc() # No plan or DB error — go to profile st.session_state._plan_checked = True if _db_err: st.session_state._login_db_err = _db_err st.switch_page("pages/1_Profile.py") else: st.session_state.login_error = msg st.query_params.clear(); st.rerun() # ── STEP 2a: SEND OTP ───────────────────────────────────────────────────────── if action == "send_otp": su = params.get("u",""); se = params.get("e","") sp = params.get("p",""); sp2 = params.get("p2","") if sp != sp2: st.session_state.signup_error = "Passwords don't match." elif "@" not in se or "." not in se: st.session_state.signup_error = "Enter a valid email address." elif len(sp) < 6: st.session_state.signup_error = "Password must be at least 6 characters." elif not su.strip(): st.session_state.signup_error = "Username is required." else: with st.spinner(""): ok, msg = initiate_signup(su.strip(), se.strip().lower(), sp) if ok: if msg == "__NO_OTP__": # Brevo not configured — user saved directly, redirect to login st.session_state.signup_success = "✓ Account created! Please sign in." st.session_state.page_mode = "login" st.session_state.signup_step = "form" st.session_state.pending_signup = {} else: # OTP sent — go to verification step st.session_state.pending_signup = {"username": su.strip(), "email": se.strip().lower(), "password": sp} st.session_state.signup_step = "otp" st.session_state.signup_error = "" st.session_state.page_mode = "signup" else: st.session_state.signup_error = msg st.session_state.page_mode = "signup" st.query_params.clear(); st.rerun() # ── STEP 2b: VERIFY OTP → STEP 3: CREATE ACCOUNT ──────────────────────────── if action == "verify_otp": otp_val = params.get("otp", "") # Data travels in URL — never relies on session_state (iframe boundary safe) su = params.get("u", "").strip() se = params.get("e", "").strip() sp = params.get("p", "").strip() if not su: # fallback (same-origin reload) pd = st.session_state.get("pending_signup", {}) su = pd.get("username",""); se = pd.get("email",""); sp = pd.get("password","") ok, token, msg = complete_signup(su, se, sp, otp_val) if ok: # STEP 4: redirect to login after account created st.session_state.signup_success = "✓ Account created! Please sign in." st.session_state.signup_step = "form" st.session_state.page_mode = "login" st.session_state.pending_signup = {} else: st.session_state.otp_error = msg st.session_state.signup_step = "otp" st.session_state.page_mode = "signup" st.query_params.clear(); st.rerun() # ── NAV ─────────────────────────────────────────────────────────────────────── if action == "go_signup": st.session_state.page_mode = "signup"; st.session_state.signup_step = "form" st.query_params.clear(); st.rerun() if action == "go_login": st.session_state.page_mode = "login" st.query_params.clear(); st.rerun() if action == "go_back": st.session_state.signup_step = "form" st.session_state.pending_signup = {} st.session_state.page_mode = "signup" st.query_params.clear(); st.rerun() # ── Pop flash messages ──────────────────────────────────────────────────────── login_error = st.session_state.pop("login_error", "") signup_error = st.session_state.pop("signup_error", "") otp_error = st.session_state.pop("otp_error", "") signup_success = st.session_state.pop("signup_success", "") mode = st.session_state.page_mode signup_step = st.session_state.signup_step pending = st.session_state.pending_signup pending_email = pending.get("email", "") pending_u = pending.get("username", "") pending_e = pending.get("email", "") pending_p = pending.get("password", "") is_signup = mode == "signup" is_landing = mode == "landing" def err(msg): return f"
We sent a 6-digit code to
" + pending_email + "Check your inbox and spam folder