dev testing
This commit is contained in:
@@ -48,7 +48,10 @@ export async function addDonor({ name, amount, classYear, message, anonymous })
|
||||
}
|
||||
|
||||
export function calculateTotal(donors) {
|
||||
return donors.reduce((sum, d) => sum + (d.amount || 0), 0);
|
||||
return donors.reduce((sum, d) => {
|
||||
if (d.status && d.status !== 'confirmed') return sum;
|
||||
return sum + (d.amount || 0);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// ===== Admin Operations =====
|
||||
|
||||
59
src/main.js
59
src/main.js
@@ -4,6 +4,7 @@ import { subscribeToDonors, calculateTotal, sortDonors } from './donors.js';
|
||||
import { subscribeToComments, addComment, deleteComment } from './comments.js';
|
||||
import { searchStudents } from './students.js';
|
||||
import { addSubscriber } from './subscribers.js';
|
||||
import { createPendingDonation, buildPaymentUrl } from './pending-donations.js';
|
||||
|
||||
// ===== State =====
|
||||
let allDonors = [];
|
||||
@@ -21,6 +22,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
initNewsletter();
|
||||
initModal();
|
||||
initStudentSearch();
|
||||
initDonationModal();
|
||||
|
||||
// Real-time Firestore listeners
|
||||
subscribeToDonors(handleDonorsUpdate);
|
||||
@@ -183,7 +185,8 @@ function initCommentForm() {
|
||||
|
||||
// ===== Donors =====
|
||||
function handleDonorsUpdate(donors) {
|
||||
allDonors = donors;
|
||||
// Only show confirmed donors (or donors without a status field for backwards compatibility)
|
||||
allDonors = donors.filter((d) => !d.status || d.status === 'confirmed');
|
||||
const total = calculateTotal(donors);
|
||||
document.getElementById('totalRaised').textContent = `$${total.toLocaleString()}`;
|
||||
renderDonors();
|
||||
@@ -377,7 +380,7 @@ function initModal() {
|
||||
// Become a Fundraiser button
|
||||
document.getElementById('becomeFundraiserBtn').addEventListener('click', () => {
|
||||
showModal(
|
||||
'<h2>Become a Fundraiser</h2><p style="margin-top:12px">Create your own fundraising page and rally your classmates! Share the donation link with friends and family to help Wesley High School reach its goal.</p><a href="https://pay.shopdm.store/dominica-methodist-circuit" target="_blank" rel="noopener" class="btn btn-primary" style="margin-top:20px;display:inline-flex">Start Fundraising</a>'
|
||||
'<h2>Become a Fundraiser</h2><p style="margin-top:12px">Create your own fundraising page and rally your classmates! Share the donation link with friends and family to help Wesley High School reach its goal.</p><button class="btn btn-primary open-donation-modal" style="margin-top:20px;display:inline-flex" onclick="document.getElementById(\'modalOverlay\').classList.add(\'hidden\');document.getElementById(\'donationModalOverlay\').classList.remove(\'hidden\')">Start Fundraising</button>'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -386,7 +389,7 @@ function initModal() {
|
||||
if (startBtn) {
|
||||
startBtn.addEventListener('click', () => {
|
||||
showModal(
|
||||
'<h2>Start Your Fundraiser</h2><p style="margin-top:12px">Share the Wesley High School donation page with your network and help us celebrate 100 years!</p><a href="https://pay.shopdm.store/dominica-methodist-circuit" target="_blank" rel="noopener" class="btn btn-primary" style="margin-top:20px;display:inline-flex">Get Started</a>'
|
||||
'<h2>Start Your Fundraiser</h2><p style="margin-top:12px">Share the Wesley High School donation page with your network and help us celebrate 100 years!</p><button class="btn btn-primary open-donation-modal" style="margin-top:20px;display:inline-flex" onclick="document.getElementById(\'modalOverlay\').classList.add(\'hidden\');document.getElementById(\'donationModalOverlay\').classList.remove(\'hidden\')">Get Started</button>'
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -397,6 +400,56 @@ function showModal(html) {
|
||||
document.getElementById('modalOverlay').classList.remove('hidden');
|
||||
}
|
||||
|
||||
// ===== Donation Modal =====
|
||||
function initDonationModal() {
|
||||
const overlay = document.getElementById('donationModalOverlay');
|
||||
const closeBtn = document.getElementById('donationModalClose');
|
||||
const form = document.getElementById('donationForm');
|
||||
const submitBtn = document.getElementById('donationSubmitBtn');
|
||||
|
||||
// Open modal from any donate button
|
||||
document.querySelectorAll('.open-donation-modal').forEach((btn) => {
|
||||
btn.addEventListener('click', () => overlay.classList.remove('hidden'));
|
||||
});
|
||||
|
||||
// Close modal
|
||||
closeBtn.addEventListener('click', () => overlay.classList.add('hidden'));
|
||||
overlay.addEventListener('click', (e) => {
|
||||
if (e.target === overlay) overlay.classList.add('hidden');
|
||||
});
|
||||
|
||||
// Handle form submission
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const name = document.getElementById('donorName').value.trim();
|
||||
const amount = document.getElementById('donorAmount').value;
|
||||
const classYear = document.getElementById('donorClassYear').value.trim();
|
||||
const message = document.getElementById('donorMessage').value.trim();
|
||||
const anonymous = document.getElementById('donorAnonymous').checked;
|
||||
|
||||
if (!name || !amount) return;
|
||||
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Processing...';
|
||||
|
||||
try {
|
||||
const pendingId = await createPendingDonation({ name, amount, classYear, message, anonymous });
|
||||
const paymentUrl = buildPaymentUrl(pendingId, amount, anonymous ? 'Anonymous' : name);
|
||||
window.open(paymentUrl, '_blank');
|
||||
overlay.classList.add('hidden');
|
||||
form.reset();
|
||||
showToast('Redirecting to payment. Complete your donation on the Shopdm Pay page.', 'success');
|
||||
} catch (error) {
|
||||
console.error('Error creating donation:', error);
|
||||
showToast('Failed to process donation. Please try again.', 'error');
|
||||
} finally {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Proceed to Payment';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Utilities =====
|
||||
function escapeHtml(str) {
|
||||
const div = document.createElement('div');
|
||||
|
||||
40
src/pending-donations.js
Normal file
40
src/pending-donations.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import { collection, addDoc, serverTimestamp } from 'firebase/firestore';
|
||||
import { db } from './firebase.js';
|
||||
|
||||
const pendingRef = collection(db, 'pendingDonations');
|
||||
|
||||
const IS_DEV = import.meta.env.DEV;
|
||||
|
||||
const MERCHANT_HANDLE = IS_DEV
|
||||
? 'dominica-methodist-circuit-dev'
|
||||
: 'dominica-methodist-circuit';
|
||||
|
||||
const PAYMENT_BASE_URL = IS_DEV
|
||||
? 'https://pay-dm-dev.web.app'
|
||||
: 'https://pay.shopdm.store';
|
||||
|
||||
export async function createPendingDonation({ name, amount, classYear, message, anonymous }) {
|
||||
const docRef = await addDoc(pendingRef, {
|
||||
name: anonymous ? 'Anonymous' : name,
|
||||
amount: Number(amount),
|
||||
classYear: classYear || '',
|
||||
message: message || '',
|
||||
anonymous: !!anonymous,
|
||||
status: 'pending',
|
||||
env: IS_DEV ? 'dev' : 'production',
|
||||
createdAt: serverTimestamp(),
|
||||
});
|
||||
return docRef.id;
|
||||
}
|
||||
|
||||
export function buildPaymentUrl(pendingId, amount, donorName) {
|
||||
const totalXcd = Number(amount).toFixed(2);
|
||||
const reason = `WHS 100th Anniversary Donation - ${donorName}`;
|
||||
const params = new URLSearchParams({
|
||||
total_xcd: totalXcd,
|
||||
reason: reason,
|
||||
invoice_id: pendingId,
|
||||
redirect: 'true',
|
||||
});
|
||||
return `${PAYMENT_BASE_URL}/${MERCHANT_HANDLE}?${params.toString()}`;
|
||||
}
|
||||
118
src/style.css
118
src/style.css
@@ -1172,6 +1172,124 @@ img {
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Thank You Page ===== */
|
||||
.thank-you-page {
|
||||
min-height: calc(100vh - 160px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 20px;
|
||||
background: var(--gray-50);
|
||||
}
|
||||
|
||||
.thank-you-card {
|
||||
max-width: 560px;
|
||||
width: 100%;
|
||||
background: var(--white);
|
||||
border-radius: 12px;
|
||||
padding: 48px 40px;
|
||||
text-align: center;
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.thank-you-icon {
|
||||
color: var(--success);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.thank-you-card h1 {
|
||||
font-size: 1.75rem;
|
||||
color: var(--primary);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.thank-you-card > p {
|
||||
color: var(--gray-600);
|
||||
line-height: 1.6;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.thank-you-actions {
|
||||
margin-top: 28px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.thank-you-actions .share-section {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.share-prompt {
|
||||
font-size: 0.9rem;
|
||||
color: var(--gray-500);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
/* ===== Donation Form ===== */
|
||||
.donation-form {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
color: var(--gray-700);
|
||||
}
|
||||
|
||||
.form-group .required {
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.form-group .optional {
|
||||
color: var(--gray-400);
|
||||
font-weight: 400;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.form-group input[type="text"],
|
||||
.form-group input[type="number"],
|
||||
.form-group textarea {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--gray-300);
|
||||
border-radius: var(--radius);
|
||||
font-family: var(--font-family);
|
||||
font-size: 0.95rem;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary);
|
||||
box-shadow: 0 0 0 3px rgba(26, 26, 110, 0.1);
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 0.9rem;
|
||||
color: var(--gray-600);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-label input[type="checkbox"] {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* ===== Responsive ===== */
|
||||
@media (max-width: 768px) {
|
||||
.hero-inner {
|
||||
|
||||
Reference in New Issue
Block a user