1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Upgrade</title> 7 <link rel="stylesheet" href="css/site.css"> 8
8<script src="js/config.js"></script>
8 9
9<script src="js/brand.js"></script>
9 10
10<script src="js/api.js"></script>
10 11
11<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
11 12</head> 13<body data-title-suffix="Upgrade"> 14 <nav class="nav"> 15 <div class="container"> 16 <a href="index.html" class="nav-brand" data-brand>Doc Engine</a> 17 <div class="nav-links"> 18 <a href="index.html">Home</a> 19 <a href="index.html#pricing">Pricing</a> 20 <a href="signup.html">Sign up</a> 21 <a href="upgrade.html">Upgrade</a> 22 <a href="manage.html">Manage billing</a> 23 </div> 24 </div> 25 </nav> 26 27 <!-- Plan picker: full-width like the pricing section on index.html --> 28 <section class="section section-alt" id="plan-picker-section"> 29 <div class="container"> 30 <h2>Choose your plan</h2> 31 <div class="price-cards" id="plan-cards" style="grid-template-columns: repeat(2, minmax(0, 320px));"> 32 <div class="card price-card"> 33 <h3>Pro</h3> 34 <div class="amount">$10<small>/month</small></div> 35 <ul> 36 <li><strong>2,000</strong> members/month</li> 37 <li>BYOK support</li> 38 <li>Cancel anytime</li> 39 </ul> 40 <button type="button" class="btn btn-primary btn-block" onclick="selectPlan('pro')">Select Pro</button> 41 </div> 42 <div class="card price-card"> 43 <h3>Pro Plus</h3> 44 <div class="amount">$25<small>/month</small></div> 45 <ul> 46 <li><strong>10,000</strong> members/month</li> 47 <li>BYOK support</li> 48 <li>Cancel anytime</li> 49 </ul> 50 <button type="button" class="btn btn-primary btn-block" onclick="selectPlan('pro_plus')">Select Pro Plus</button> 51 </div> 52 </div> 53 <p class="price-note">Don't have a token yet? <a href="signup.html">Sign up free first</a>.</p> 54 </div> 55 </section> 56 57 <!-- Checkout form: narrow, shown after plan is selected --> 58 <div class="form-page" id="checkout-section" hidden> 59 <p id="selected-plan-label" style="margin-bottom:1rem"></p> 60 <div id="error-box" class="alert alert-error" hidden></div> 61 <form id="upgrade-form"> 62 <div class="field"> 63 <label for="token">Your API token</label> 64 <input type="password" id="token" name="token" required autocomplete="off" placeholder="Paste your token"> 65 </div> 66 <button type="submit" id="submit-btn" class="btn btn-primary btn-block">Continue to payment</button> 67 </form> 68 <p class="form-footnote"><a href="#" onclick="resetPlan(); return false;">â Choose a different plan</a></p> 69 </div> 70 71 <!-- Success --> 72 <div class="form-page" id="success-section" hidden style="text-align:center"> 73 <h1>You're on <span id="success-plan-name"></span>!</h1> 74 <div class="alert alert-ok">Payment confirmed. Your account is now upgraded.</div> 75 <p>Your existing token keeps working â nothing to change in the extension.</p> 76 <a href="index.html" class="btn btn-primary" style="margin-top:1rem">Back to home</a> 77 </div> 78 79
79<script> 80 const PLANS = { 81 pro: { label: "Pro â $10/month (2,000 members/month)", name: "Pro" }, 82 pro_plus: { label: "Pro Plus â $25/month (10,000 members/month)", name: "Pro Plus" }, 83 }; 84 85 let selectedTier = null; 86 87 function selectPlan(tier) { 88 selectedTier = tier; 89 document.getElementById("selected-plan-label").innerHTML = 90 "Plan: <strong>" + PLANS[tier].label + "</strong>"; 91 document.getElementById("plan-picker-section").hidden = true; 92 document.getElementById("checkout-section").hidden = false; 93 document.getElementById("error-box").hidden = true; 94 document.getElementById("token").value = ""; 95 document.getElementById("submit-btn").disabled = false; 96 document.getElementById("submit-btn").textContent = "Continue to payment"; 97 } 98 99 function resetPlan() { 100 selectedTier = null; 101 document.getElementById("plan-picker-section").hidden = false; 102 document.getElementById("checkout-section").hidden = true; 103 } 104 105 const form = document.getElementById("upgrade-form"); 106 const errorBox = document.getElementById("error-box"); 107 const submitBtn = document.getElementById("submit-btn"); 108 109 form.addEventListener("submit", async (e) => { 110 e.preventDefault(); 111 hideError(errorBox); 112 const token = document.getElementById("token").value.trim(); 113 if (!token) { 114 showError(errorBox, "Please paste your API token."); 115 return; 116 } 117 submitBtn.disabled = true; 118 submitBtn.textContent = "Loadingâ¦"; 119 120 let checkoutData;
121 try { 122 checkoutData = await apiPost("/billing/checkout", { tier: selectedTier }, token); 123 } catch (err) { 124 if (err.status === 401) { 125 showError(errorBox, "That token isn't valid. Check for missing characters and try again."); 126 } else { 127 showError(errorBox, "Couldn't reach the server. Please try again in a minute."); 128 } 129 submitBtn.disabled = false; 130 submitBtn.textContent = "Continue to payment"; 131 return; 132 } 133 134 const planName = PLANS[selectedTier].name; 135 const rzp = new Razorpay({ 136 key: checkoutData.key_id, 137 subscription_id: checkoutData.subscription_id, 138 name: SITE_CONFIG.BRAND_NAME, 139 description: planName + " Plan", 140 theme: { color: "#2563eb" }, 141 handler: async function (response) { 142 submitBtn.textContent = "Confirming paymentâ¦"; 143 try { 144 await apiPost("/billing/verify", { 145 razorpay_payment_id: response.razorpay_payment_id, 146 razorpay_subscription_id: response.razorpay_subscription_id, 147 razorpay_signature: response.razorpay_signature, 148 }, token); 149 document.getElementById("success-plan-name").textContent = planName; 150 document.getElementById("checkout-section").hidden = true; 151 document.getElementById("success-section").hidden = false; 152 } catch (err) { 153 showError( 154 errorBox, 155 "Payment received but verification failed â contact support with payment ID: " + 156 response.razorpay_payment_id 157 ); 158 submitBtn.disabled = false; 159 submitBtn.textContent = "Continue to payment"; 160 } 161 }, 162 modal: { 163 ondismiss: function () { 164 submitBtn.disabled = false; 165 submitBtn.textContent = "Continue to payment"; 166 } 167 } 168 }); 169 rzp.open(); 170 }); 171 </script>
171 172 173 <footer class="footer"> 174 <div class="container"> 175 <span data-brand>Doc Engine</span> 176 <span> 177 <a href="index.html#pricing">Pricing</a> 178 <a href="signup.html">Sign up</a> 179 <a href="upgrade.html">Upgrade</a> 180 <a href="manage.html">Manage billing</a> 181 </span> 182 <span>© Vericodex</span> 183 </div> 184 </footer> 185</body> 186</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.