/* VA Classes, homepage UI kit · reusable components */ /* ── Lead endpoint fallback — set on every page via components.jsx ── */ if (!window.VA_LEAD_ENDPOINT) { window.VA_LEAD_ENDPOINT = "https://script.google.com/macros/s/AKfycbxUjyJHhLAqiyh8A4SzB7tl7Zc_sgmHiTIHaynfftoqcBO_mvUJP37ZHqfVu7YknWNnTw/exec"; } /* ===================================================================== LINKS, single place for all external URLs. ▶ Replace the "#" placeholders with the real URLs: - login: your student/parent portal LOGIN url (login only, no public sign-up) - facebook / instagram / trustpilot: your social & review pages ===================================================================== */ window.VA_LINKS = window.VA_LINKS || { login: "https://merithub.com/login", facebook: "#facebook", instagram: "https://www.instagram.com/va__classes", trustpilot: "https://www.trustpilot.com/review/vaclasses.live", }; const LINKS = window.VA_LINKS; const NAV_SUBJECTS = [ { name: "Math", icon: "calculator", page: "math.html", grades: "Grades 1 to 10" }, { name: "Science", icon: "atom", page: "science.html", grades: "Grades 1 to 10" }, { name: "English", icon: "book-open", page: "english.html", grades: "Grades 1 to 10" }, { name: "Coding", icon: "code-xml", page: "coding.html", grades: "Grades 3 to 10" }, ]; function Icon({ name, size = 18, style }) { return ; } function useLucide() { React.useEffect(() => { if (window.lucide) window.lucide.createIcons(); }); } function Logo({ light = false, boxed = false }) { if (boxed) { return ( VA Classes VA Classes ); } const markSrc = light ? "assets/logo-mark-light.png" : "assets/logo-mark.png"; return ( VA Classes VA Classes ); } function Button({ variant = "primary", size, children, onClick, icon, iconRight }) { const cls = ["btn", `btn-${variant}`, size && `btn-${size}`].filter(Boolean).join(" "); return ( ); } // Star rating row, green (#00B67A) like Trustpilot function Stars({ rating = 5, size = 14 }) { return ( {[0, 1, 2, 3, 4].map(i => ( ))} ); } function PhotoPlaceholder({ caption, glyph = "users", radius = "var(--r-xl)", minHeight = 380 }) { return (
{caption}
); } function SubjectCard({ s }) { return (

{s.name}

{s.desc}

Explore {s.name}
); } function TutorAvatar({ t }) { const palette = ["#FF6B6B", "#FFC700", "#4ECDC4", "#5B8DEF", "#C77DFF", "#FF9F1C", "#1F8A4C", "#2A9DEF"]; const color = palette[(t.name ? t.name.charCodeAt(0) : 0) % palette.length]; if (t.photo) return
{t.name}
; return
{t.name ? t.name[0] : "?"}
; } function TutorCard({ t, onBook }) { return (

{t.name}

{t.rating.toFixed(1)}· {t.reviews} reviews
{t.subject} {t.experience}+ yrs
{t.bio &&

{t.bio}

}
{t.education} {t.location}
); } function TestimonialCard({ q, feat = false }) { return (
{q.flag && }
“{q.quote}”
{q.name ? q.name[0] : ""}
{q.name}
{q.role}
); } function PriceTier({ tier, cycle, currency }) { const cur = currency || "cad"; const price = tier.price[cur][cycle]; const prefix = cur === "cad" ? "CA$" : "US$"; const label = cur === "cad" ? "CAD" : "USD"; return (
{tier.popular && Most popular}

{tier.name}

{prefix}{price} /{cycle === "quarter" ? "quarter" : "month"}

{tier.sub} Billed in {label}

); } // ---- Shared chrome (used by every page) ---- function LoginLink({ small = true }) { return ( Log in ); } function SubjectsMenu() { const [open, setOpen] = React.useState(false); const ref = React.useRef(null); React.useEffect(() => { const close = e => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }; document.addEventListener("click", close); return () => document.removeEventListener("click", close); }, []); React.useEffect(() => { if (open && window.lucide) window.lucide.createIcons(); }, [open]); return (
{open && (
{NAV_SUBJECTS.map(s => ( setOpen(false)}> {s.name}{s.grades} ))}
)}
); } function Nav({ onTrial }) { useLucide(); const [mOpen, setMOpen] = React.useState(false); const navRef = React.useRef(null); // Add shadow when page is scrolled React.useEffect(() => { const onScroll = () => { if (navRef.current) { navRef.current.classList.toggle("is-scrolled", window.scrollY > 10); } }; window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); React.useEffect(() => { if (!mOpen) return; const close = () => setMOpen(false); document.addEventListener("click", close); return () => document.removeEventListener("click", close); }, [mOpen]); return ( ); } function SocialIcon({ kind }) { if (kind === "facebook") return ( ); if (kind === "instagram") return ( ); return ( ); } function Footer() { const cols = [ { h: "Subjects", links: [["Math", "math.html"], ["Science", "science.html"], ["English", "english.html"], ["Coding", "coding.html"]] }, { h: "Company", links: [["About us", "about.html"], ["Pricing", "pricing.html"], ["Contact us", "contact.html"], ["Teach with us", "tutor.html"]] }, { h: "For families", links: [["Book a free class", "index.html#top"], ["Log in", LINKS.login], ["Reviews on Trustpilot", LINKS.trustpilot], ["Privacy policy", "privacy.html"], ["Terms of service", "terms.html"]] }, ]; const socials = [ { kind: "facebook", label: "Facebook", href: LINKS.facebook, bg: "#1877F2" }, { kind: "instagram", label: "Instagram", href: LINKS.instagram, bg: "linear-gradient(135deg,#f09433,#e6683c,#dc2743,#cc2366,#bc1888)" }, { kind: "trustpilot", label: "Trustpilot", href: LINKS.trustpilot, bg: "#00B67A" }, ]; useLucide(); return ( ); } const ALL_SUBJECTS = ["Math", "Science", "English", "Coding"]; function SubjectPicker({ value, onChange }) { const toggle = (s) => onChange(value.includes(s) ? value.filter(x => x !== s) : [...value, s]); return (
{ALL_SUBJECTS.map(s => ( ))}
); } function TrialModal({ onClose }) { const [step, setStep] = React.useState(1); const [done, setDone] = React.useState(false); const [sending, setSending] = React.useState(false); const [f, setF] = React.useState({ parent: "", email: "", phone: "", province: "Ontario", child: "", grade: "5", subjects: ["Math"], schedule: "Weekday evenings", goal: "", heard: "", }); const set = (k, v) => setF(prev => ({ ...prev, [k]: v })); useLucide(); // Sends the lead to your Google Sheet + Gmail (see LEAD_ENDPOINT in components.jsx). const submitLead = () => { setSending(true); const payload = { ...f, subjects: f.subjects.join(", "), source: "Detailed form", submittedAt: new Date().toLocaleString("en-CA"), page: location.href, }; // Always show success to the parent; lead is sent in the background. const finish = () => { setSending(false); setDone(true); }; if (window.VA_LEAD_ENDPOINT && window.VA_LEAD_ENDPOINT.startsWith("http")) { fetch(window.VA_LEAD_ENDPOINT, { method: "POST", mode: "no-cors", headers: { "Content-Type": "text/plain;charset=utf-8" }, body: JSON.stringify(payload), }).then(finish).catch(finish); } else { console.warn("VA_LEAD_ENDPOINT not set — lead not sent:", payload); finish(); } }; const canNext = f.parent.trim() && f.email.trim(); const total = 2; return (
e.stopPropagation()}> {!done ? (

Book your free class

Step {step} of {total} · {step === 1 ? "About you" : "About your child"}

{step === 1 ? (
set("parent", e.target.value)} />
set("email", e.target.value)} />
set("phone", e.target.value)} />

No card required · 100% free trial class

) : (
set("child", e.target.value)} />
set("subjects", v)} />
)}
) : (

You're booked{f.child ? `, ${f.parent.split(" ")[0]}!` : "!"}

We'll email {f.email || "you"} within a few hours to confirm {f.child || "your child"}'s free {f.subjects.join(" & ")} trial. Talk soon!

)}
); } function FAQ({ items }) { const [open, setOpen] = React.useState(0); return (
{items.map((it, i) => (
{open === i &&
{it.a}
}
))}
); } function WhyDifferent({ subjectName }) { const C = window.VA_COMPARE; const cell = (v) => { if (v === true) return ; if (v === "some") return Sometimes; return ; }; useLucide(); return (

Why we're different

{subjectName ? `Why families choose VA Classes for ${subjectName}` : "What sets VA Classes apart"}

Studies are consistent: one-on-one tutoring is the most effective way to learn, because lessons adapt to your child, feedback is instant, and there's no crowd to hide behind. Here's how the three options really compare.

{/* header row */}
VA Classes
Group online
classes
Self-study
apps
{/* data rows */} {C.rows.map((r, i) => (
{r.f}
{cell(r.va)}
{cell(r.group)}
{cell(r.app)}
))}
); } function IncludedGrid() { useLucide(); return (

Included in every plan

Every plan comes with all of this

No hidden tiers for the things that matter. These come standard, whichever plan you pick.

{window.VA_INCLUDED.map(it => (

{it.t}

{it.d}

))}
); } Object.assign(window, { Icon, useLucide, Logo, Button, Stars, PhotoPlaceholder, SubjectCard, TutorCard, TestimonialCard, PriceTier, Nav, Footer, TrialModal, LoginLink, SubjectsMenu, FAQ, SubjectPicker, SocialIcon, WhyDifferent, IncludedGrid });