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

4
dist/admin.html vendored
View File

@@ -8,8 +8,8 @@
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<script type="module" crossorigin src="/assets/admin-BaZpN3Uw.js"></script>
<link rel="modulepreload" crossorigin href="/assets/donors-DDFnEjnq.js">
<script type="module" crossorigin src="/assets/admin-CsJ8T6K2.js"></script>
<link rel="modulepreload" crossorigin href="/assets/donors-BfBdprwo.js">
<link rel="stylesheet" crossorigin href="/assets/admin-r6G2dek0.css">
</head>
<body>

View File

@@ -1,4 +1,4 @@
import{i as C,j as A,n as p,p as D,f as b,d as S,v as k,x as M,y as $,t as x,z as T,A as F,B as Y,C as N}from"./donors-DDFnEjnq.js";const f=["pcgurudm@gmail.com"];let m=[];document.addEventListener("DOMContentLoaded",()=>{C(),H(),V(),P(),j(),_()});function H(){document.getElementById("loginGoogle").addEventListener("click",A),document.getElementById("logoutBtn").addEventListener("click",p),document.getElementById("unauthorizedLogout").addEventListener("click",p),D(q)}async function q(t){const e=document.getElementById("authSection"),n=document.getElementById("unauthorizedSection"),o=document.getElementById("adminContent"),d=document.getElementById("logoutBtn");if(!t){e.classList.remove("hidden"),n.classList.add("hidden"),o.classList.add("hidden"),d.style.display="none";return}if(d.style.display="",!await z(t.email)){e.classList.add("hidden"),n.classList.remove("hidden"),o.classList.add("hidden");return}e.classList.add("hidden"),n.classList.add("hidden"),o.classList.remove("hidden"),g()}async function z(t){try{const e=b(S,"config","admins"),n=await k(e);return n.exists()?(n.data()?.emails||[]).includes(t):f.includes(t)?(await M(e,{emails:f}),console.log("Admin allowlist created with seed admins."),!0):!1}catch(e){return console.error("Admin check failed:",e),!1}}function V(){document.querySelectorAll(".admin-tab").forEach(t=>{t.addEventListener("click",()=>{document.querySelectorAll(".admin-tab").forEach(e=>e.classList.remove("active")),document.querySelectorAll(".admin-panel").forEach(e=>e.classList.remove("active")),t.classList.add("active"),document.getElementById(`panel-${t.dataset.tab}`).classList.add("active")})})}async function g(){try{m=await $(),R(),L()}catch(t){console.error("Failed to load donors:",t),r("Failed to load donors.","error")}}function R(){const t=x(m);document.getElementById("statTotal").textContent=`$${t.toLocaleString()}`,document.getElementById("statCount").textContent=m.length}function P(){const t=document.getElementById("addDonorForm");t.addEventListener("submit",async e=>{e.preventDefault();const n=document.getElementById("addDonorBtn");n.disabled=!0,n.textContent="Adding...";try{await T({name:document.getElementById("donorName").value.trim(),amount:document.getElementById("donorAmount").value,classYear:document.getElementById("donorClassYear").value.trim(),message:document.getElementById("donorMessage").value.trim(),anonymous:document.getElementById("donorAnonymous").checked,date:document.getElementById("donorDate").value||null}),r("Donor added!","success"),t.reset(),await g()}catch(o){console.error("Failed to add donor:",o),r("Failed to add donor.","error")}finally{n.disabled=!1,n.textContent="Add Donor"}})}let u=[],h=[];function j(){document.getElementById("csvFile").addEventListener("change",G),document.getElementById("importBtn").addEventListener("click",O),document.getElementById("csvCancelBtn").addEventListener("click",I),document.querySelectorAll(".mapping-grid select").forEach(e=>{e.addEventListener("change",B)})}function G(t){const e=t.target.files[0];if(!e)return;const n=new FileReader;n.onload=o=>{const d=o.target.result,a=U(d);if(a.length<2){r("CSV file appears empty or has no data rows.","error");return}h=a[0],u=a.slice(1),W(),document.getElementById("csvMapping").classList.remove("hidden")},n.readAsText(e)}function U(t){const e=[];let n=[],o="",d=!1;for(let a=0;a<t.length;a++){const s=t[a],i=t[a+1];d?s==='"'&&i==='"'?(o+='"',a++):s==='"'?d=!1:o+=s:s==='"'?d=!0:s===","?(n.push(o.trim()),o=""):s===`
import{i as C,j as A,k as p,m as D,f as b,d as S,t as k,u as M,v as $,p as x,x as T,y as F,z as Y,A as N}from"./donors-BfBdprwo.js";const f=["pcgurudm@gmail.com"];let m=[];document.addEventListener("DOMContentLoaded",()=>{C(),H(),V(),P(),j(),_()});function H(){document.getElementById("loginGoogle").addEventListener("click",A),document.getElementById("logoutBtn").addEventListener("click",p),document.getElementById("unauthorizedLogout").addEventListener("click",p),D(q)}async function q(t){const e=document.getElementById("authSection"),n=document.getElementById("unauthorizedSection"),o=document.getElementById("adminContent"),d=document.getElementById("logoutBtn");if(!t){e.classList.remove("hidden"),n.classList.add("hidden"),o.classList.add("hidden"),d.style.display="none";return}if(d.style.display="",!await z(t.email)){e.classList.add("hidden"),n.classList.remove("hidden"),o.classList.add("hidden");return}e.classList.add("hidden"),n.classList.add("hidden"),o.classList.remove("hidden"),g()}async function z(t){try{const e=b(S,"config","admins"),n=await k(e);return n.exists()?(n.data()?.emails||[]).includes(t):f.includes(t)?(await M(e,{emails:f}),console.log("Admin allowlist created with seed admins."),!0):!1}catch(e){return console.error("Admin check failed:",e),!1}}function V(){document.querySelectorAll(".admin-tab").forEach(t=>{t.addEventListener("click",()=>{document.querySelectorAll(".admin-tab").forEach(e=>e.classList.remove("active")),document.querySelectorAll(".admin-panel").forEach(e=>e.classList.remove("active")),t.classList.add("active"),document.getElementById(`panel-${t.dataset.tab}`).classList.add("active")})})}async function g(){try{m=await $(),R(),L()}catch(t){console.error("Failed to load donors:",t),r("Failed to load donors.","error")}}function R(){const t=x(m);document.getElementById("statTotal").textContent=`$${t.toLocaleString()}`,document.getElementById("statCount").textContent=m.length}function P(){const t=document.getElementById("addDonorForm");t.addEventListener("submit",async e=>{e.preventDefault();const n=document.getElementById("addDonorBtn");n.disabled=!0,n.textContent="Adding...";try{await T({name:document.getElementById("donorName").value.trim(),amount:document.getElementById("donorAmount").value,classYear:document.getElementById("donorClassYear").value.trim(),message:document.getElementById("donorMessage").value.trim(),anonymous:document.getElementById("donorAnonymous").checked,date:document.getElementById("donorDate").value||null}),r("Donor added!","success"),t.reset(),await g()}catch(o){console.error("Failed to add donor:",o),r("Failed to add donor.","error")}finally{n.disabled=!1,n.textContent="Add Donor"}})}let u=[],h=[];function j(){document.getElementById("csvFile").addEventListener("change",G),document.getElementById("importBtn").addEventListener("click",O),document.getElementById("csvCancelBtn").addEventListener("click",I),document.querySelectorAll(".mapping-grid select").forEach(e=>{e.addEventListener("change",B)})}function G(t){const e=t.target.files[0];if(!e)return;const n=new FileReader;n.onload=o=>{const d=o.target.result,a=U(d);if(a.length<2){r("CSV file appears empty or has no data rows.","error");return}h=a[0],u=a.slice(1),W(),document.getElementById("csvMapping").classList.remove("hidden")},n.readAsText(e)}function U(t){const e=[];let n=[],o="",d=!1;for(let a=0;a<t.length;a++){const s=t[a],i=t[a+1];d?s==='"'&&i==='"'?(o+='"',a++):s==='"'?d=!1:o+=s:s==='"'?d=!0:s===","?(n.push(o.trim()),o=""):s===`
`||s==="\r"&&i===`
`?(n.push(o.trim()),n.some(l=>l!=="")&&e.push(n),n=[],o="",s==="\r"&&a++):o+=s}return n.push(o.trim()),n.some(a=>a!=="")&&e.push(n),e}function W(){const t=["mapName","mapAmount","mapClassYear","mapMessage","mapDate","mapAnonymous"],e={mapName:["name","donor","first","full"],mapAmount:["amount","donation","gift","total","sum"],mapClassYear:["class","year","grad"],mapMessage:["message","note","comment"],mapDate:["date","time","when"],mapAnonymous:["anonymous","anon"]};for(const n of t){const o=document.getElementById(n);o.innerHTML='<option value="">-- skip --</option>',h.forEach((s,i)=>{const l=document.createElement("option");l.value=i,l.textContent=s,o.appendChild(l)});const d=e[n],a=h.findIndex(s=>d.some(i=>s.toLowerCase().includes(i)));a!==-1&&(o.value=a)}B()}function E(t){const e=n=>{const o=document.getElementById(n).value;return o!==""&&t[Number(o)]||""};return{name:e("mapName"),amount:e("mapAmount"),classYear:e("mapClassYear"),message:e("mapMessage"),date:e("mapDate"),anonymous:e("mapAnonymous")}}function B(){const t=document.getElementById("csvPreviewHead"),e=document.getElementById("csvPreviewBody");t.innerHTML="<tr><th>Name</th><th>Amount</th><th>Class Year</th><th>Date</th><th>Message</th><th>Anon</th></tr>";const n=u.slice(0,5);e.innerHTML=n.map(o=>{const d=E(o);return`<tr>
<td>${c(d.name)}</td>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

32
dist/assets/main-CCpTsy09.js vendored Normal file
View File

@@ -0,0 +1,32 @@
import{c as y,d as u,q as B,o as I,a as A,b as f,s as v,e as k,f as T,l as M,w as E,g as U,i as D,h as N,j as R,k as H,m as P,n as F,p as q,r as C}from"./donors-BfBdprwo.js";/* empty css */const S=y(u,"comments");let b=null;function O(e){const o=B(S,I("timestamp","desc"));return b=A(o,n=>{const t=[];n.forEach(a=>{t.push({id:a.id,...a.data()})}),e(t)},n=>{console.error("Error fetching comments:",n),e([])}),b}async function Y(e,o){return!e||!o.trim()?null:f(S,{userId:e.uid,userName:e.displayName||"Anonymous",userPhoto:e.photoURL||"",text:o.trim(),timestamp:v()})}async function _(e){return k(T(u,"comments",e))}const j=y(u,"students");async function W(e){const o=e.trim().toLowerCase();if(!o)return[];const n=o+"",t=B(j,E("nameLower",">=",o),E("nameLower","<=",n),I("nameLower"),M(50));try{const a=await U(t),s=[];return a.forEach(r=>{s.push({id:r.id,...r.data()})}),s}catch(a){return console.error("Error searching students:",a),[]}}const G=y(u,"subscribers");async function J(e){return f(G,{email:e,subscribedAt:v()})}const X=y(u,"pendingDonations"),z="dominica-methodist-circuit",K="https://pay.shopdm.store";async function Q({name:e,amount:o,classYear:n,message:t,anonymous:a}){return(await f(X,{name:a?"Anonymous":e,amount:Number(o),classYear:n||"",message:t||"",anonymous:!!a,status:"pending",env:"production",createdAt:v()})).id}function V(e,o,n){const t=Number(o).toFixed(2),a=`WHS 100th Anniversary Donation - ${n}`,s=new URLSearchParams({total_xcd:t,reason:a,invoice_id:e,redirect:"true"});return`${K}/${z}?${s.toString()}`}let w=[],g=[];document.addEventListener("DOMContentLoaded",()=>{D(),Z(),ee(),te(),ne(),se(),ie(),me(),ue(),le(),he(),N(re),O(de)});function Z(){const e=document.getElementById("tabNav");e.addEventListener("click",o=>{const n=o.target.closest(".tab-btn");if(!n)return;e.querySelectorAll(".tab-btn").forEach(a=>a.classList.remove("active")),n.classList.add("active"),document.querySelectorAll(".tab-panel").forEach(a=>a.classList.remove("active"));const t=document.getElementById(`tab-${n.dataset.tab}`);t&&t.classList.add("active")})}function ee(){const e=document.getElementById("carouselTrack"),o=e.querySelectorAll(".carousel-slide"),n=document.querySelectorAll(".dot"),t=document.getElementById("carouselPrev"),a=document.getElementById("carouselNext");let s=0,r;function i(c){s=(c%o.length+o.length)%o.length,e.style.transform=`translateX(-${s*100}%)`,n.forEach((p,$)=>p.classList.toggle("active",$===s))}function l(){h(),r=setInterval(()=>i(s+1),5e3)}function h(){clearInterval(r)}t.addEventListener("click",()=>{i(s-1),l()}),a.addEventListener("click",()=>{i(s+1),l()}),n.forEach(c=>{c.addEventListener("click",()=>{i(Number(c.dataset.index)),l()})}),l()}function te(){const e=window.location.href,o="Wesley High School - 100th Anniversary Fundraiser",n="Support Wesley High School's 100th Anniversary Celebrations! Help us celebrate a century of excellence.";document.getElementById("shareFacebook").addEventListener("click",()=>{window.open(`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(e)}`,"_blank","width=600,height=400")}),document.getElementById("shareTwitter").addEventListener("click",()=>{window.open(`https://twitter.com/intent/tweet?text=${encodeURIComponent(n)}&url=${encodeURIComponent(e)}`,"_blank","width=600,height=400")}),document.getElementById("shareEmail").addEventListener("click",()=>{window.location.href=`mailto:?subject=${encodeURIComponent(o)}&body=${encodeURIComponent(n+`
`+e)}`})}function ne(){document.getElementById("loginGoogle").addEventListener("click",R),document.getElementById("logoutBtn").addEventListener("click",H),P(oe)}function oe(e){const o=document.getElementById("authPrompt"),n=document.getElementById("commentForm"),t=document.getElementById("userAvatar"),a=document.getElementById("userName");e?(o.classList.add("hidden"),n.classList.remove("hidden"),t.src=e.photoURL||ae(e.displayName||"U"),t.alt=e.displayName||"User",a.textContent=e.displayName||e.email||"User"):(o.classList.remove("hidden"),n.classList.add("hidden"))}function ae(e){const o=e.charAt(0).toUpperCase(),n=document.createElement("canvas");n.width=80,n.height=80;const t=n.getContext("2d");return t.fillStyle="#1a1a6e",t.fillRect(0,0,80,80),t.fillStyle="#ffffff",t.font="bold 36px Inter, sans-serif",t.textAlign="center",t.textBaseline="middle",t.fillText(o,40,40),n.toDataURL()}function se(){const e=document.getElementById("commentText"),o=document.getElementById("charCount"),n=document.getElementById("postCommentBtn");e.addEventListener("input",()=>{o.textContent=`${e.value.length}/500`}),n.addEventListener("click",async()=>{const t=C(),a=e.value.trim();if(!(!t||!a)){n.disabled=!0,n.textContent="Posting...";try{await Y(t,a),e.value="",o.textContent="0/500"}catch(s){console.error("Error posting comment:",s),m("Failed to post comment. Please try again.","error")}finally{n.disabled=!1,n.textContent="Post Comment"}}})}function re(e){w=e.filter(n=>!n.status||n.status==="confirmed");const o=q(e);document.getElementById("totalRaised").textContent=`$${o.toLocaleString()}`,x()}function ie(){document.getElementById("donorSort").addEventListener("change",x)}function x(){const e=document.getElementById("donorsList"),o=document.getElementById("donorsEmpty"),n=document.getElementById("donorSort").value,t=F(w,n);if(t.length===0){e.innerHTML="",e.appendChild(o),o.classList.remove("hidden");return}e.innerHTML=t.map(a=>{const s=(a.name||"A").charAt(0).toUpperCase(),r=a.date?.toDate?a.date.toDate().toLocaleDateString():"",i=a.classYear?` &middot; Class of ${a.classYear}`:"";return`
<div class="donor-card">
<div class="donor-info">
<div class="donor-avatar">${s}</div>
<div class="donor-details">
<h4>${d(a.name)}</h4>
<p>${r}${i}</p>
${a.message?`<p style="margin-top:4px;color:#374151;font-size:0.85rem">"${d(a.message)}"</p>`:""}
</div>
</div>
<div class="donor-amount">$${(a.amount||0).toLocaleString()}</div>
</div>`}).join("")}function de(e){g=e,ce()}function ce(){const e=document.getElementById("commentsList"),o=document.getElementById("commentsEmpty"),n=C();if(g.length===0){e.innerHTML="",e.appendChild(o),o.classList.remove("hidden");return}e.innerHTML=g.map(t=>{const a=t.timestamp?.toDate?ye(t.timestamp.toDate()):"just now",s=t.userPhoto?`<img class="comment-avatar" src="${d(t.userPhoto)}" alt="${d(t.userName)}" />`:`<div class="comment-avatar-placeholder">${(t.userName||"U").charAt(0).toUpperCase()}</div>`,r=n&&n.uid===t.userId?`<button class="comment-delete" data-id="${t.id}">Delete</button>`:"";return`
<div class="comment-card">
${s}
<div class="comment-body">
<div class="comment-header">
<span class="comment-author">${d(t.userName)}</span>
<span class="comment-time">${a}</span>
</div>
<p class="comment-text">${d(t.text)}</p>
${r}
</div>
</div>`}).join(""),e.querySelectorAll(".comment-delete").forEach(t=>{t.addEventListener("click",async()=>{if(confirm("Delete this comment?"))try{await _(t.dataset.id)}catch(a){console.error("Error deleting comment:",a),m("Failed to delete comment.","error")}})})}function le(){const e=document.getElementById("studentSearch"),o=document.getElementById("studentResults"),n=document.getElementById("studentSearchEmpty");let t;e.addEventListener("input",()=>{clearTimeout(t);const a=e.value.trim();if(!a){o.innerHTML="",o.appendChild(n),n.querySelector("p").textContent="Enter a name above to search for students.",n.classList.remove("hidden");return}t=setTimeout(async()=>{o.innerHTML='<div class="search-loading"><div class="loading-spinner"></div> Searching...</div>';const s=await W(a);if(s.length===0){o.innerHTML="",o.appendChild(n),n.querySelector("p").textContent=`No students found matching "${d(a)}".`,n.classList.remove("hidden");return}o.innerHTML=s.map(r=>`
<div class="student-card">
<div class="student-avatar">${(r.name||"?").charAt(0).toUpperCase()}</div>
<div class="student-info">
<h4>${d(r.name)}</h4>
<p>Class of ${d(String(r.classYear||"N/A"))}</p>
</div>
</div>`).join("")},350)})}function me(){const e=document.getElementById("newsletterForm"),o=e.querySelector('button[type="submit"]');e.addEventListener("submit",async n=>{n.preventDefault();const t=document.getElementById("newsletterEmail").value.trim();if(t){o.disabled=!0,o.textContent="Joining...";try{await J(t),m("Thank you for subscribing!","success"),e.reset()}catch(a){console.error("Newsletter subscribe error:",a),m("Failed to subscribe. Please try again.","error")}finally{o.disabled=!1,o.textContent="Join"}}})}function ue(){const e=document.getElementById("modalOverlay");document.getElementById("modalClose").addEventListener("click",()=>e.classList.add("hidden")),e.addEventListener("click",t=>{t.target===e&&e.classList.add("hidden")}),document.getElementById("becomeFundraiserBtn").addEventListener("click",()=>{L(`<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>`)});const n=document.getElementById("startFundraiserBtn");n&&n.addEventListener("click",()=>{L(`<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>`)})}function L(e){document.getElementById("modalContent").innerHTML=e,document.getElementById("modalOverlay").classList.remove("hidden")}function he(){const e=document.getElementById("donationModalOverlay"),o=document.getElementById("donationModalClose"),n=document.getElementById("donationForm"),t=document.getElementById("donationSubmitBtn");document.querySelectorAll(".open-donation-modal").forEach(a=>{a.addEventListener("click",()=>e.classList.remove("hidden"))}),o.addEventListener("click",()=>e.classList.add("hidden")),e.addEventListener("click",a=>{a.target===e&&e.classList.add("hidden")}),n.addEventListener("submit",async a=>{a.preventDefault();const s=document.getElementById("donorName").value.trim(),r=document.getElementById("donorAmount").value,i=document.getElementById("donorClassYear").value.trim(),l=document.getElementById("donorMessage").value.trim(),h=document.getElementById("donorAnonymous").checked;if(!(!s||!r)){t.disabled=!0,t.textContent="Processing...";try{const c=await Q({name:s,amount:r,classYear:i,message:l,anonymous:h}),p=V(c,r,h?"Anonymous":s);window.open(p,"_blank"),e.classList.add("hidden"),n.reset(),m("Redirecting to payment. Complete your donation on the Shopdm Pay page.","success")}catch(c){console.error("Error creating donation:",c),m("Failed to process donation. Please try again.","error")}finally{t.disabled=!1,t.textContent="Proceed to Payment"}}})}function d(e){const o=document.createElement("div");return o.textContent=e||"",o.innerHTML}function ye(e){const o=Math.floor((Date.now()-e.getTime())/1e3);if(o<60)return"just now";const n=Math.floor(o/60);if(n<60)return`${n}m ago`;const t=Math.floor(n/60);if(t<24)return`${t}h ago`;const a=Math.floor(t/24);if(a<30)return`${a}d ago`;const s=Math.floor(a/30);return s<12?`${s}mo ago`:`${Math.floor(s/12)}y ago`}function m(e,o="info"){const n=document.querySelector(".toast");n&&n.remove();const t=document.createElement("div");t.className=`toast ${o}`,t.textContent=e,document.body.appendChild(t),setTimeout(()=>t.remove(),4e3)}

View File

@@ -1,32 +0,0 @@
import{c as p,d as u,q as v,o as E,a as k,b,s as L,e as T,f as A,l as U,w as g,g as D,i as M,h as N,j as H,k as F,m as R,n as q,p as P,r as j,t as W,u as B}from"./donors-DDFnEjnq.js";const I=p(u,"comments");let y=null;function Y(t){const n=v(I,E("timestamp","desc"));return y=k(n,o=>{const e=[];o.forEach(s=>{e.push({id:s.id,...s.data()})}),t(e)},o=>{console.error("Error fetching comments:",o),t([])}),y}async function _(t,n){return!t||!n.trim()?null:b(I,{userId:t.uid,userName:t.displayName||"Anonymous",userPhoto:t.photoURL||"",text:n.trim(),timestamp:L()})}async function G(t){return T(A(u,"comments",t))}const O=p(u,"students");async function J(t){const n=t.trim().toLowerCase();if(!n)return[];const o=n+"",e=v(O,g("nameLower",">=",n),g("nameLower","<=",o),E("nameLower"),U(50));try{const s=await D(e),a=[];return s.forEach(r=>{a.push({id:r.id,...r.data()})}),a}catch(s){return console.error("Error searching students:",s),[]}}const z=p(u,"subscribers");async function X(t){return b(z,{email:t,subscribedAt:L()})}let C=[],h=[];document.addEventListener("DOMContentLoaded",()=>{M(),K(),Q(),V(),Z(),nt(),st(),ct(),dt(),it(),N(ot),Y(at)});function K(){const t=document.getElementById("tabNav");t.addEventListener("click",n=>{const o=n.target.closest(".tab-btn");if(!o)return;t.querySelectorAll(".tab-btn").forEach(s=>s.classList.remove("active")),o.classList.add("active"),document.querySelectorAll(".tab-panel").forEach(s=>s.classList.remove("active"));const e=document.getElementById(`tab-${o.dataset.tab}`);e&&e.classList.add("active")})}function Q(){const t=document.getElementById("carouselTrack"),n=t.querySelectorAll(".carousel-slide"),o=document.querySelectorAll(".dot"),e=document.getElementById("carouselPrev"),s=document.getElementById("carouselNext");let a=0,r;function c(l){a=(l%n.length+n.length)%n.length,t.style.transform=`translateX(-${a*100}%)`,o.forEach((x,$)=>x.classList.toggle("active",$===a))}function d(){S(),r=setInterval(()=>c(a+1),5e3)}function S(){clearInterval(r)}e.addEventListener("click",()=>{c(a-1),d()}),s.addEventListener("click",()=>{c(a+1),d()}),o.forEach(l=>{l.addEventListener("click",()=>{c(Number(l.dataset.index)),d()})}),d()}function V(){const t=window.location.href,n="Wesley High School - 100th Anniversary Fundraiser",o="Support Wesley High School's 100th Anniversary Celebrations! Help us celebrate a century of excellence.";document.getElementById("shareFacebook").addEventListener("click",()=>{window.open(`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(t)}`,"_blank","width=600,height=400")}),document.getElementById("shareTwitter").addEventListener("click",()=>{window.open(`https://twitter.com/intent/tweet?text=${encodeURIComponent(o)}&url=${encodeURIComponent(t)}`,"_blank","width=600,height=400")}),document.getElementById("shareEmail").addEventListener("click",()=>{window.location.href=`mailto:?subject=${encodeURIComponent(n)}&body=${encodeURIComponent(o+`
`+t)}`})}function Z(){document.getElementById("loginGoogle").addEventListener("click",H),document.getElementById("loginFacebook").addEventListener("click",F),document.getElementById("loginTwitter").addEventListener("click",R),document.getElementById("logoutBtn").addEventListener("click",q),P(tt)}function tt(t){const n=document.getElementById("authPrompt"),o=document.getElementById("commentForm"),e=document.getElementById("userAvatar"),s=document.getElementById("userName");t?(n.classList.add("hidden"),o.classList.remove("hidden"),e.src=t.photoURL||et(t.displayName||"U"),e.alt=t.displayName||"User",s.textContent=t.displayName||t.email||"User"):(n.classList.remove("hidden"),o.classList.add("hidden"))}function et(t){const n=t.charAt(0).toUpperCase(),o=document.createElement("canvas");o.width=80,o.height=80;const e=o.getContext("2d");return e.fillStyle="#1a1a6e",e.fillRect(0,0,80,80),e.fillStyle="#ffffff",e.font="bold 36px Inter, sans-serif",e.textAlign="center",e.textBaseline="middle",e.fillText(n,40,40),o.toDataURL()}function nt(){const t=document.getElementById("commentText"),n=document.getElementById("charCount"),o=document.getElementById("postCommentBtn");t.addEventListener("input",()=>{n.textContent=`${t.value.length}/500`}),o.addEventListener("click",async()=>{const e=B(),s=t.value.trim();if(!(!e||!s)){o.disabled=!0,o.textContent="Posting...";try{await _(e,s),t.value="",n.textContent="0/500"}catch(a){console.error("Error posting comment:",a),m("Failed to post comment. Please try again.","error")}finally{o.disabled=!1,o.textContent="Post Comment"}}})}function ot(t){C=t;const n=W(t);document.getElementById("totalRaised").textContent=`$${n.toLocaleString()}`,w()}function st(){document.getElementById("donorSort").addEventListener("change",w)}function w(){const t=document.getElementById("donorsList"),n=document.getElementById("donorsEmpty"),o=document.getElementById("donorSort").value,e=j(C,o);if(e.length===0){t.innerHTML="",t.appendChild(n),n.classList.remove("hidden");return}t.innerHTML=e.map(s=>{const a=(s.name||"A").charAt(0).toUpperCase(),r=s.date?.toDate?s.date.toDate().toLocaleDateString():"",c=s.classYear?` &middot; Class of ${s.classYear}`:"";return`
<div class="donor-card">
<div class="donor-info">
<div class="donor-avatar">${a}</div>
<div class="donor-details">
<h4>${i(s.name)}</h4>
<p>${r}${c}</p>
${s.message?`<p style="margin-top:4px;color:#374151;font-size:0.85rem">"${i(s.message)}"</p>`:""}
</div>
</div>
<div class="donor-amount">$${(s.amount||0).toLocaleString()}</div>
</div>`}).join("")}function at(t){h=t,rt()}function rt(){const t=document.getElementById("commentsList"),n=document.getElementById("commentsEmpty"),o=B();if(h.length===0){t.innerHTML="",t.appendChild(n),n.classList.remove("hidden");return}t.innerHTML=h.map(e=>{const s=e.timestamp?.toDate?lt(e.timestamp.toDate()):"just now",a=e.userPhoto?`<img class="comment-avatar" src="${i(e.userPhoto)}" alt="${i(e.userName)}" />`:`<div class="comment-avatar-placeholder">${(e.userName||"U").charAt(0).toUpperCase()}</div>`,r=o&&o.uid===e.userId?`<button class="comment-delete" data-id="${e.id}">Delete</button>`:"";return`
<div class="comment-card">
${a}
<div class="comment-body">
<div class="comment-header">
<span class="comment-author">${i(e.userName)}</span>
<span class="comment-time">${s}</span>
</div>
<p class="comment-text">${i(e.text)}</p>
${r}
</div>
</div>`}).join(""),t.querySelectorAll(".comment-delete").forEach(e=>{e.addEventListener("click",async()=>{if(confirm("Delete this comment?"))try{await G(e.dataset.id)}catch(s){console.error("Error deleting comment:",s),m("Failed to delete comment.","error")}})})}function it(){const t=document.getElementById("studentSearch"),n=document.getElementById("studentResults"),o=document.getElementById("studentSearchEmpty");let e;t.addEventListener("input",()=>{clearTimeout(e);const s=t.value.trim();if(!s){n.innerHTML="",n.appendChild(o),o.querySelector("p").textContent="Enter a name above to search for students.",o.classList.remove("hidden");return}e=setTimeout(async()=>{n.innerHTML='<div class="search-loading"><div class="loading-spinner"></div> Searching...</div>';const a=await J(s);if(a.length===0){n.innerHTML="",n.appendChild(o),o.querySelector("p").textContent=`No students found matching "${i(s)}".`,o.classList.remove("hidden");return}n.innerHTML=a.map(r=>`
<div class="student-card">
<div class="student-avatar">${(r.name||"?").charAt(0).toUpperCase()}</div>
<div class="student-info">
<h4>${i(r.name)}</h4>
<p>Class of ${i(String(r.classYear||"N/A"))}</p>
</div>
</div>`).join("")},350)})}function ct(){const t=document.getElementById("newsletterForm"),n=t.querySelector('button[type="submit"]');t.addEventListener("submit",async o=>{o.preventDefault();const e=document.getElementById("newsletterEmail").value.trim();if(e){n.disabled=!0,n.textContent="Joining...";try{await X(e),m("Thank you for subscribing!","success"),t.reset()}catch(s){console.error("Newsletter subscribe error:",s),m("Failed to subscribe. Please try again.","error")}finally{n.disabled=!1,n.textContent="Join"}}})}function dt(){const t=document.getElementById("modalOverlay");document.getElementById("modalClose").addEventListener("click",()=>t.classList.add("hidden")),t.addEventListener("click",e=>{e.target===t&&t.classList.add("hidden")}),document.getElementById("becomeFundraiserBtn").addEventListener("click",()=>{f('<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>')});const o=document.getElementById("startFundraiserBtn");o&&o.addEventListener("click",()=>{f('<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>')})}function f(t){document.getElementById("modalContent").innerHTML=t,document.getElementById("modalOverlay").classList.remove("hidden")}function i(t){const n=document.createElement("div");return n.textContent=t||"",n.innerHTML}function lt(t){const n=Math.floor((Date.now()-t.getTime())/1e3);if(n<60)return"just now";const o=Math.floor(n/60);if(o<60)return`${o}m ago`;const e=Math.floor(o/60);if(e<24)return`${e}h ago`;const s=Math.floor(e/24);if(s<30)return`${s}d ago`;const a=Math.floor(s/30);return a<12?`${a}mo ago`:`${Math.floor(a/12)}y ago`}function m(t,n="info"){const o=document.querySelector(".toast");o&&o.remove();const e=document.createElement("div");e.className=`toast ${n}`,e.textContent=t,document.body.appendChild(e),setTimeout(()=>e.remove(),4e3)}

1
dist/assets/style-B2qcWQAK.css vendored Normal file

File diff suppressed because one or more lines are too long

BIN
dist/images/logo-black.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

BIN
dist/images/logo-blue.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

BIN
dist/images/logo-blue.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 KiB

BIN
dist/images/logo-orange.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

58
dist/index.html vendored
View File

@@ -9,9 +9,9 @@
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<script type="module" crossorigin src="/assets/main-f9-9VaoM.js"></script>
<link rel="modulepreload" crossorigin href="/assets/donors-DDFnEjnq.js">
<link rel="stylesheet" crossorigin href="/assets/main-BYboBf7A.css">
<script type="module" crossorigin src="/assets/main-CCpTsy09.js"></script>
<link rel="modulepreload" crossorigin href="/assets/donors-BfBdprwo.js">
<link rel="stylesheet" crossorigin href="/assets/style-B2qcWQAK.css">
</head>
<body>
<!-- Top Header Bar -->
@@ -32,7 +32,7 @@
<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>
</a>
</div>
<a href="https://pay.shopdm.store/dominica-methodist-circuit" target="_blank" rel="noopener" class="btn btn-donate-header">Donate</a>
<button class="btn btn-donate-header open-donation-modal">Donate</button>
</div>
</div>
</header>
@@ -94,7 +94,7 @@
<span class="amount" id="totalRaised">$0</span>
<span class="label">Total Raised</span>
</div>
<a href="https://pay.shopdm.store/dominica-methodist-circuit" target="_blank" rel="noopener" class="btn btn-primary btn-large">Make a Donation</a>
<button class="btn btn-primary btn-large open-donation-modal">Make a Donation</button>
<button class="btn btn-outline btn-large" id="becomeFundraiserBtn">Become a Fundraiser</button>
</div>
</div>
@@ -154,7 +154,7 @@
<p>Wesley High School has been a cornerstone of education in Dominica since 1926. As we celebrate our centennial, we invite all alumni, students, and supporters to contribute to our legacy.</p>
<p>Our goal is to raise funds that will support scholarships, and a science lab for our students.</p>
<div class="about-cta">
<a href="https://pay.shopdm.store/dominica-methodist-circuit" target="_blank" rel="noopener" class="btn btn-primary">Donate Now</a>
<button class="btn btn-primary open-donation-modal">Donate Now</button>
</div>
<!-- Share Section -->
@@ -218,7 +218,7 @@
<div class="donors-list" id="donorsList">
<div class="empty-state" id="donorsEmpty">
<p>No donations yet. Be the first to donate!</p>
<a href="https://pay.shopdm.store/dominica-methodist-circuit" target="_blank" rel="noopener" class="btn btn-primary">Make a Donation</a>
<button class="btn btn-primary open-donation-modal">Make a Donation</button>
</div>
</div>
</div>
@@ -235,14 +235,6 @@
<svg viewBox="0 0 24 24" width="18" height="18"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z"/><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/></svg>
Sign in with Google
</button>
<button class="btn btn-auth btn-facebook" id="loginFacebook">
<svg viewBox="0 0 24 24" fill="#fff" width="18" height="18"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>
Sign in with Facebook
</button>
<button class="btn btn-auth btn-twitter" id="loginTwitter">
<svg viewBox="0 0 24 24" fill="#fff" width="18" height="18"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
Sign in with X
</button>
</div>
</div>
<div class="comment-form hidden" id="commentForm">
@@ -297,6 +289,42 @@
</div>
</footer>
<!-- Donation Modal -->
<div class="modal-overlay hidden" id="donationModalOverlay">
<div class="modal" id="donationModal">
<button class="modal-close" id="donationModalClose">&times;</button>
<div class="modal-content">
<h2>Make a Donation</h2>
<p style="margin-top:8px;color:#4b5563">Your information will appear on our donors wall after payment.</p>
<form id="donationForm" class="donation-form">
<div class="form-group">
<label for="donorName">Name <span class="required">*</span></label>
<input type="text" id="donorName" placeholder="Your full name" required />
</div>
<div class="form-group">
<label for="donorAmount">Amount (XCD) <span class="required">*</span></label>
<input type="number" id="donorAmount" placeholder="e.g. 100" min="1" step="0.01" required />
</div>
<div class="form-group">
<label for="donorClassYear">Class Year <span class="optional">(optional)</span></label>
<input type="text" id="donorClassYear" placeholder="e.g. 1995" />
</div>
<div class="form-group">
<label for="donorMessage">Message <span class="optional">(optional)</span></label>
<textarea id="donorMessage" placeholder="Leave a message of support..." rows="3" maxlength="255"></textarea>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="donorAnonymous" />
Make my donation anonymous
</label>
</div>
<button type="submit" class="btn btn-primary btn-large" id="donationSubmitBtn">Proceed to Payment</button>
</form>
</div>
</div>
</div>
<!-- Login Modal (for showing auth errors) -->
<div class="modal-overlay hidden" id="modalOverlay">
<div class="modal" id="modal">

82
dist/thank-you.html vendored Normal file
View File

@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Thank You - Wesley High School Fundraiser</title>
<meta name="description" content="Thank you for your donation to Wesley High School's 100th Anniversary Celebrations." />
<link rel="icon" type="image/svg+xml" href="/images/favicon.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" crossorigin href="/assets/style-B2qcWQAK.css">
</head>
<body>
<!-- Top Header Bar -->
<header class="top-bar">
<div class="top-bar-inner">
<div class="top-bar-left">
<a href="/">
<img src="/images/logo-white.png" alt="Wesley High School" class="top-bar-logo" />
</a>
</div>
<div class="top-bar-right">
<div class="social-icons">
<a href="https://www.facebook.com/WesleyHighSchoolDominica" target="_blank" rel="noopener" aria-label="Facebook" class="social-icon">
<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>
</a>
</div>
</div>
</div>
</header>
<main class="thank-you-page">
<div class="thank-you-card">
<div class="thank-you-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="64" height="64">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
<polyline points="22 4 12 14.01 9 11.01" />
</svg>
</div>
<h1>Thank You for Your Donation!</h1>
<p>Your generous contribution to the Wesley High School 100th Anniversary Fund has been received and is being processed.</p>
<p>Your name will appear on our donors wall shortly. Together, we are building the next 100 years of excellence.</p>
<div class="thank-you-actions">
<a href="/" class="btn btn-primary btn-large">Return to Homepage</a>
<div class="share-section">
<p class="share-prompt">Spread the word and help us reach our goal!</p>
<div class="share-buttons">
<button class="share-btn share-facebook" id="shareFacebook">
<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>
Share on Facebook
</button>
<button class="share-btn share-email" id="shareEmail">
<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/></svg>
Share via Email
</button>
</div>
</div>
</div>
</div>
</main>
<footer class="site-footer">
<div class="footer-bottom">
<p>Copyright &copy; 2026 Wesley High School. All rights reserved.</p>
</div>
</footer>
<script>
const siteUrl = 'https://alumni.whsdominica.com/';
const text = 'I just donated to Wesley High School\'s 100th Anniversary Fund! Join me in supporting a century of excellence.';
document.getElementById('shareFacebook').addEventListener('click', () => {
window.open('https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(siteUrl), '_blank', 'width=600,height=400');
});
document.getElementById('shareEmail').addEventListener('click', () => {
window.location.href = 'mailto:?subject=' + encodeURIComponent('Support Wesley High School') + '&body=' + encodeURIComponent(text + '\n\n' + siteUrl);
});
</script>
</body>
</html>