PageSourceSearch

https://docengine.pages.dev/upgrade

html docengine.pages.dev collected 2026-10-03 05:10:17 UTC 7,206 bytes, 186 lines download raw bytes

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>&copy; 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.