dev testing

This commit is contained in:
2026-03-23 15:29:13 -04:00
parent 28dae0dc60
commit d772b7ec9c
5664 changed files with 863006 additions and 73 deletions

View File

@@ -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 =====

View File

@@ -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
View 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()}`;
}

View File

@@ -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 {