import { useState, useEffect } from "react"; import { useNavigate, useSearchParams } from "react-router-dom"; import { useAuth } from "../../contexts/AuthContext"; import { useUserProperties } from "../../contexts/UserPropertiesContext"; import { createOnboardingCheckout, verifyCheckoutSession, activateFreeTier, } from "../../api/stripe"; import Input from "../../components/Input"; import Button from "../../components/Button"; import TierPicker from "../../components/TierPicker"; import "./Subscribe.css"; const STEPS = ["Create Account", "Choose Plan"]; export default function Subscribe() { const { currentUser, signup } = useAuth(); const { state: userProps, dispatch, ACTION_TYPES } = useUserProperties(); const navigate = useNavigate(); const [searchParams, setSearchParams] = useSearchParams(); const hasPaymentReturn = searchParams.get("payment") === "success"; const [step, setStep] = useState(hasPaymentReturn || currentUser ? 2 : 1); const [loading, setLoading] = useState(hasPaymentReturn); const [error, setError] = useState(""); const [data, setData] = useState({ selectedTier: "", email: "", password: "", confirmPassword: "", }); function set(field, value) { setData((prev) => ({ ...prev, [field]: value })); } // Handle Stripe payment returns useEffect(() => { const payment = searchParams.get("payment"); const sessionId = searchParams.get("session_id"); const signupLockKey = sessionId ? `kp_onboard_signup_started_${sessionId}` : null; if (payment === "cancelled") { if (signupLockKey) sessionStorage.removeItem(signupLockKey); sessionStorage.removeItem("kp_onboard_email"); sessionStorage.removeItem("kp_onboard_pw"); setSearchParams({}, { replace: true }); setStep(2); setError("Payment was cancelled. Please try again."); return; } if (payment !== "success" || !sessionId) return; // Phase 1: no account yet — create it. Auth state change remounts the // component (App.jsx swaps route trees) and Phase 2 runs on the next mount. if (!currentUser) { const savedEmail = sessionStorage.getItem("kp_onboard_email"); const savedPw = sessionStorage.getItem("kp_onboard_pw"); if (!savedEmail || !savedPw) { if (signupLockKey) sessionStorage.removeItem(signupLockKey); setSearchParams({}, { replace: true }); setError("Session expired. Please start the signup process again."); setStep(1); setLoading(false); return; } // Guard against duplicate signup attempts caused by repeated effects. if (signupLockKey && sessionStorage.getItem(signupLockKey) === "1") { setLoading(true); return; } setLoading(true); if (signupLockKey) sessionStorage.setItem(signupLockKey, "1"); signup(savedEmail, savedPw).catch((err) => { if (signupLockKey) sessionStorage.removeItem(signupLockKey); setSearchParams({}, { replace: true }); setError("Account creation failed: " + err.message); setStep(1); setLoading(false); }); return; } // Phase 2: authenticated — verify the checkout and go to the dashboard. setSearchParams({}, { replace: true }); setLoading(true); dispatch({ type: ACTION_TYPES.CLEAR_USER_PROPERTIES }); verifyCheckoutSession(sessionId) .then(() => { navigate("/addresses", { replace: true }); }) .catch((err) => { setError("Payment verification failed: " + err.message); setStep(2); }) .finally(() => setLoading(false)); }, [currentUser, searchParams, setSearchParams, signup, navigate, userProps, dispatch, ACTION_TYPES]); // ── Step handlers ───────────────────────────────────────────────────────── function handleStep1() { setError(""); if (!data.email || !data.password || !data.confirmPassword) { setError("Please fill in all fields"); return; } if (data.password !== data.confirmPassword) { setError("Passwords do not match"); return; } if (data.password.length < 6) { setError("Password must be at least 6 characters"); return; } setStep(2); } async function handleStep2() { setError(""); if (!data.selectedTier) { setError("Please select a plan to continue"); return; } try { setLoading(true); if (data.selectedTier === "free") { if (!currentUser) { await signup(data.email, data.password); } await activateFreeTier(); navigate("/addresses", { replace: true }); return; } dispatch({ type: ACTION_TYPES.SET_USER_PROPERTIES, payload: { email: data.email, password: data.password }, }); const { url } = await createOnboardingCheckout( data.email, data.selectedTier, ); window.location.href = url; } catch (err) { if (err.code === "auth/email-already-in-use") { setError("Email already in use. Try logging in instead."); } else if (err.code === "auth/invalid-email") { setError("Invalid email address"); } else if (err.code === "auth/weak-password") { setError("Password is too weak"); } else { setError("Failed to process plan selection: " + err.message); } } finally { setLoading(false); } } // ── Progress bar ────────────────────────────────────────────────────────── function ProgressBar() { return (
Select the plan that works best for you. You can upgrade anytime.
Already have an account? Log in here
)}