Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 262 additions & 0 deletions donate.html
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,55 @@
font-weight: 600;
}
/* --- END NEW STYLES FOR RAZORPAY BUTTON INTEGRATION --- */

/* --- Custom Subscription Form (UI polish) --- */
.subscription-card .custom-subscription-form { text-align: left; margin-top: .25rem; }
.subscription-card .custom-subscription-form .form-group label { font-weight: 600; color: var(--brand-dark-grey); font-size: 0.95rem; }
.subscription-card .custom-subscription-form .form-section-title {
font-weight: 700;
font-size: 0.95rem;
color: var(--brand-red);
margin: .5rem 0 .5rem;
letter-spacing: .2px;
}
.subscription-card .custom-subscription-form .input-group-text {
background-color: var(--brand-beige);
border-color: var(--brand-beige);
color: var(--brand-dark-grey);
}
.subscription-card .custom-subscription-form .form-control:focus {
border-color: var(--brand-red);
box-shadow: 0 0 0 0.2rem rgba(167, 13, 23, 0.15);
}
.subscription-card .custom-subscription-form .btn { margin-top: 0.25rem; }
/* On small screens keep single column; md and above uses .col-md-6 already */
@media (min-width: 992px) { /* lg and up */
.subscription-card .custom-subscription-form .form-row > [class^="col-"] { margin-bottom: .75rem; }
}

/* Match Razorpay Subscribe button look & feel for our custom button */
.subscription-card .custom-subscription-form .SubscriptionButton {
width: 100%;
background: rgb(255, 124, 4);
color: #fff;
border: none;
border-radius: 6px;
padding: 12px 16px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
cursor: pointer;
font-weight: 600;
text-decoration: none;
}
.subscription-card .custom-subscription-form .SubscriptionButton:hover {
background: rgb(230, 110, 0);
}
.subscription-card .custom-subscription-form .SubscriptionButton svg {
display: inline-block;
}
.subscription-card .custom-subscription-form .SubscriptionButton-text { font-weight: 600; }
/* --- Styles for In-Kind Section --- */
.in-kind-details {
background-color: #fff;
Expand Down Expand Up @@ -892,6 +941,77 @@ <h5>Amrita Sindhu (Ocean of Nectar)</h5>
</div>
</div>

<!-- Tier 10: Seva Ratna (₹5,000+) -->
<div class="col-lg-4 col-md-6 mb-4">
<div class="subscription-card" id="custom-patron-tier">
<div>
<div class="tier-icon"><i class="fas fa-crown"></i></div>
<h5>Seva Ratna (Jewel of Service)</h5>
<div class="amount">₹5,000+ / month</div>
<p class="description">Offer a custom monthly commitment (₹5,000 and above) as a Seva Ratna to sustain all Seva activities. You can modify or cancel anytime via Razorpay.</p>
</div>
<div class="razorpay-form-wrapper custom-subscription-form" id="custom-subscription-form-container">
<div class="form-group">
<label for="custom-subscription-amount" class="mb-1">Monthly Amount (₹) <span class="text-danger">*</span></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-rupee-sign" aria-hidden="true"></i></span>
</div>
<input type="number" class="form-control" id="custom-subscription-amount" min="5000" step="1" placeholder="5000" inputmode="numeric" aria-label="Monthly Amount in Rupees" required>
</div>
<small class="form-text text-muted" id="amount-help-text">Minimum ₹5,000.</small>
</div>
<h6 class="form-section-title">Your Details</h6>
<div class="form-row">
<div class="form-group col-12 col-md-6 mb-2">
<label for="custom-subscriber-name" class="mb-1">Name <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="custom-subscriber-name" placeholder="Your full name" required>
</div>
<div class="form-group col-12 col-md-6 mb-2">
<label for="custom-subscriber-email" class="mb-1">Email <span class="text-danger">*</span></label>
<input type="email" class="form-control" id="custom-subscriber-email" placeholder="you@example.com" required>
</div>
</div>
<div class="form-row">
<div class="form-group col-12 col-md-6 mb-2">
<label for="custom-subscriber-phone" class="mb-1">Phone <span class="text-danger">*</span></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fas fa-phone" aria-hidden="true"></i></span>
</div>
<input type="tel" class="form-control" id="custom-subscriber-phone" placeholder="9876543210" required>
</div>
<small class="form-text text-muted">Enter your 10-15 digit mobile number.</small>
</div>
<div class="form-group col-12 col-md-6 mb-2">
<label for="custom-subscriber-pan" class="mb-1">PAN No <span class="text-danger">*</span></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="far fa-id-card" aria-hidden="true"></i></span>
</div>
<input type="text" class="form-control" id="custom-subscriber-pan" placeholder="ABCDE1234F" maxlength="10" required>
</div>
<small class="form-text text-muted">Required for 80G</small>
</div>
</div>
<div class="form-group mb-3">
<label for="custom-subscriber-address" class="mb-1">Address <span class="text-danger">*</span></label>
<textarea class="form-control" id="custom-subscriber-address" rows="2" placeholder="House/Street, Area, City, State, PIN" required></textarea>
</div>
<button type="button" id="custom-subscribe-btn" class="SubscriptionButton SubscriptionButton--dark" aria-label="Subscribe Now">
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
<path d="M7.077 6.476l-.988 3.569 5.65-3.589-3.695 13.54 3.752.004 5.457-20L7.077 6.476z" fill="#fff"></path>
<path d="M1.455 14.308L0 20h7.202L10.149 8.42l-8.694 5.887z" fill="#fff"></path>
</svg>
<div class="SubscriptionButton-contents">
<span class="SubscriptionButton-text">Subscribe Now</span>
</div>
</button>
<small class="text-muted d-block mt-2">Secured by Razorpay. You will authorize a monthly charge.</small>
</div>
</div>
</div>

</div> <!-- End Row for Monthly -->
<div class="tax-info mt-4"> <!-- Re-emphasize tax benefit -->
<p class="mb-0"><i class="fas fa-check-circle text-success"></i> All recurring donations are eligible for tax exemption under Section 80G.</p>
Expand Down Expand Up @@ -1044,6 +1164,24 @@ <h5 class="demi mb-3">Legal</h5>

<script defer src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"></script>

<!-- Configure backend endpoint (Supabase Edge Function) -->
<script>
window.SUBSCRIPTION_API_URL = "https://huderljsxxbnrwvuhihj.supabase.co/functions/v1/create-subscription";
// To change environments, override this value before the main script block.
// Set the base plan unit in rupees (e.g., 100 for ₹100 plan, 1 for ₹1 plan)
window.SUBSCRIPTION_PLAN_UNIT_RUPEES = 100;
// Update help text to reflect multiples if applicable
(function(){
var unit = Number(window.SUBSCRIPTION_PLAN_UNIT_RUPEES || 0);
if (unit > 1) {
var el = document.getElementById('amount-help-text');
if (el) {
el.textContent = 'Minimum ₹5,000. Enter multiples of ₹' + unit + '.';
}
}
})();
</script>

<!-- BEGIN main script block -->

<script>
Expand Down Expand Up @@ -1175,6 +1313,10 @@ <h5 class="demi mb-3">Legal</h5>
const subscriptionForms = document.querySelectorAll('.subscription-card .razorpay-form-wrapper');

subscriptionForms.forEach(form => {
// Skip auto-select for the custom patron card to let donors choose among high-value options
if (form.id === 'custom-subscription-form-container' || (form.closest('#custom-patron-tier') !== null)) {
return;
}
// Set up observer for each form
const observer = new MutationObserver((mutationsList, obs) => {
// Check for the radio button once Razorpay injects content
Expand Down Expand Up @@ -1221,6 +1363,8 @@ <h5 class="demi mb-3">Legal</h5>
let checkInterval = setInterval(() => {
const uncheckedRadios = document.querySelectorAll('.subscription-card .razorpay-form-wrapper input[type="radio"][name="plan_id"]:not(:checked)');
uncheckedRadios.forEach(radio => {
// Do not force-check radios that belong to the custom patron card
if (radio.closest('#custom-patron-tier')) return;
radio.checked = true;
radio.dispatchEvent(new Event('change', { bubbles: true }));
});
Expand All @@ -1233,6 +1377,124 @@ <h5 class="demi mb-3">Legal</h5>

}); // End of DOMContentLoaded

// ---- Custom Amount Subscription Flow (Razorpay Checkout + serverless) ----
// Requires a backend endpoint at /api/create-subscription that creates a subscription
// using a base plan (e.g., ₹100/month) and sets quantity = amount/100.
// The endpoint should return { subscription_id, key_id }.
(function setupCustomSubscriptionFlow(){
const btn = document.getElementById('custom-subscribe-btn');
if (!btn) return;
// Ensure Razorpay Checkout is available (load if needed)
const ensureCheckoutScript = () => new Promise((resolve, reject) => {
if (window.Razorpay) return resolve();
const s = document.createElement('script');
s.src = 'https://checkout.razorpay.com/v1/checkout.js';
s.onload = () => resolve();
s.onerror = () => reject(new Error('Failed to load Razorpay Checkout'));
document.head.appendChild(s);
});

const getInputVal = (id) => {
const el = document.getElementById(id);
return el ? el.value.trim() : '';
};

btn.addEventListener('click', async () => {
const amountStr = getInputVal('custom-subscription-amount');
const name = getInputVal('custom-subscriber-name');
const email = getInputVal('custom-subscriber-email');
const contact = getInputVal('custom-subscriber-phone');
let pan = getInputVal('custom-subscriber-pan');
const address = getInputVal('custom-subscriber-address');
const parsed = parseInt(amountStr, 10);
if (isNaN(parsed) || parsed < 5000) {
alert('Please enter a valid monthly amount of ₹5,000 or more.');
return;
}
// Client-side unit multiple validation (configurable)
const unitRupees = Number(window.SUBSCRIPTION_PLAN_UNIT_RUPEES || 0);
if (unitRupees > 1 && (parsed % unitRupees !== 0)) {
alert('Please enter amount in multiples of ₹' + unitRupees + '.');
return;
}

// Required field checks
if (!name) { alert('Name is required.'); return; }
if (!email) { alert('Email is required.'); return; }
// Simple email check
const emailOk = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
if (!emailOk) { alert('Please enter a valid email address.'); return; }
if (!contact) { alert('Phone is required.'); return; }
// digits and length 10-15
const phoneDigits = contact.replace(/\D/g, '');
if (phoneDigits.length < 10 || phoneDigits.length > 15) { alert('Please enter a valid phone number (10-15 digits).'); return; }
if (!pan) { alert('PAN No is required.'); return; }
pan = pan.toUpperCase();
const panOk = /^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(pan);
if (!panOk) { alert('Please enter a valid PAN (e.g., ABCDE1234F).'); return; }
if (!address || address.length < 10) { alert('Please enter your full address.'); return; }

btn.disabled = true;
btn.textContent = 'Preparing…';

try {
await ensureCheckoutScript();

// Use configurable endpoint. If window.SUBSCRIPTION_API_URL is set (e.g., Supabase), use that.
const SUBSCRIPTION_API_URL = (typeof window !== 'undefined' && window.SUBSCRIPTION_API_URL)
? window.SUBSCRIPTION_API_URL
: '/api/create-subscription';

const isSupabaseFn = /\.supabase\.co\//.test(SUBSCRIPTION_API_URL);
const headers = { 'Content-Type': 'application/json' };
if (isSupabaseFn && typeof window.SUPABASE_ANON_KEY === 'string' && window.SUPABASE_ANON_KEY.length > 0) {
headers['Authorization'] = `Bearer ${window.SUPABASE_ANON_KEY}`;
}

const resp = await fetch(SUBSCRIPTION_API_URL, {
method: 'POST',
headers,
body: JSON.stringify({ amount: parsed, donor: { name, email, contact: phoneDigits, pan, address } })
});

if (!resp.ok) {
const t = await resp.text();
if (resp.status === 401 && /Missing authorization header/i.test(t)) {
throw new Error('Authorization required to call Supabase Function. Set window.SUPABASE_ANON_KEY (Anon public key) or deploy the function with no-verify-jwt.');
}
throw new Error('Server error: ' + t);
}
const { subscription_id, key_id, message } = await resp.json();
if (!subscription_id || !key_id) {
throw new Error(message || 'Invalid server response.');
}

const rzp = new window.Razorpay({
key: key_id,
subscription_id,
name: 'Ashraya Trust',
description: 'Custom Monthly Patron Subscription',
theme: { color: '#A70D17' },
prefill: { name, email, contact },
notes: { tier: 'Seva Ratna', source: 'donate.html', pan, address },
handler: function (response) {
// response.razorpay_payment_id, response.razorpay_subscription_id, response.razorpay_signature
alert('Thank you! Your subscription setup is complete.');
},
modal: { ondismiss: function () { /* User closed checkout */ } }
});
rzp.open();
} catch (err) {
console.error(err);
alert('Could not start subscription. Please try again or contact us.');
} finally {
btn.disabled = false;
btn.textContent = 'Subscribe Monthly';
}
});
})();
// ---- End Custom Amount Subscription Flow ----

// **** REVISED Web Share API Logic for all share triggers ****
document.addEventListener('DOMContentLoaded', (event) => {
const shareTriggers = document.querySelectorAll('.share-trigger');
Expand Down