1 -> 2 -> 3 -> 4 (5 steps)
Returning : Step 0 -> 2.5 -> 3 -> 4 (4 steps)
One-Off : ONE-OFF PLACEHOLDER
============================================================ -->
Q1. Type of Registration *
Please select the option that best describes you.
condensed single-step form -> Step 4.
For now this card is visible but treated as New Registration. -->
⚠️ Please select a registration type.
Q2. Programme Plan *
Please select the plan that best suits your family.
⚠️ Please select a programme plan.
Q3. Session Date(s) *
Please select your preferred session date(s) from the calendar below.
⚠️ Please select at least the first session date.
Activity and Interests
⚠️ Please tell us your child's favourite activities.
⚠️ Please select your child's current activity level.
Guardian Involvement
⚠️ Please indicate your preferred level of involvement.
Child's Current Support Level
Please select honestly — it helps us support your child better.
⚠️ Please select your child's support level.
Q4. Your Registered Email Address *
This must match the email address used in your previous registration.
Looking up your records, please wait...
We found your complete records. Please review your details below before continuing to the next step.
Basic Details
Q4.
Participant Name
—
Q5.
Contact Number
—
Q6.
Age
—
Advanced Details
Q7.
Parent / Guardian Name
—
Q8.
Parent Contact
—
Q9.
Parent Email
—
Q10.
Emergency Contact Name
—
Q11.
Emergency Contact Number
—
Q12.
Emergency Contact Email
—
We found some of your records, but some details appear to be missing. Fields showing "—" could not be retrieved. We recommend clicking Previous and selecting New Registration to re-fill the complete form so your registration is accurate.
Basic Details
Q4.
Participant Name
—
Q5.
Contact Number
—
Q6.
Age
—
Advanced Details
Q7.
Parent / Guardian Name
—
Q8.
Parent Contact
—
Q9.
Parent Email
—
Q10.
Emergency Contact Name
—
Q11.
Emergency Contact Number
—
Q12.
Emergency Contact Email
—
Sorry, No Data Were Found
Please click the Previous button and select New Registration. Thank you.
"Thank you for trusting us with your child's journey. Every child is unique, and your insights help us create a safe, joyful, and empowering experience. We look forward to supporting your child's growth towards independence and confidence."
Your Registration Summary
—
Q45. Payment Method *
Upload your payment proof below. If you are unable to upload, please WhatsApp 010-650 0838 or email hello@care2run.my.
Parents / Guardians: You do not need to pay to support your child.
QR CodeBank Transfer
DuitNow QR
Touch n Go QR
Bank: CIMB Bank
Account Name: Wildpac Asia PLT
Account Number: 800-783-044-8
Please use your child's full name as the transaction reference.
Q46. Payment Receipt *
Please attach your payment slip or screenshot (JPEG, PNG, PDF, HEIC).
⚠️ Please upload your payment receipt before submitting.
Once you submit this form, you will receive a confirmation email shortly. For any queries, please email us at
hello@care2run.my or reach us via WhatsApp: +6010-650 0838
document.addEventListener('DOMContentLoaded', function () {
/* ============================================================
ROUTE DEFINITIONS
New Registration : Step 0 -> 1 -> 2 -> 3 -> 4 ("Step X of 5")
Returning : Step 0 -> 25 -> 3 -> 4 ("Step X of 4")
One-Off : ONE-OFF PLACEHOLDER
============================================================ */
var ROUTES = {
'New Registration': { steps: [0, 1, 2, 3, 4], total: 5 },
'Returning Registration': { steps: [0, 25, 3, 4], total: 4 },
'One-Off Registration': { steps: [0, 1, 2, 3, 4], total: 5 }
};
var ALL_DOM_STEPS = [0, 1, 2, 25, 3, 4];
var currentDomStep = 0;
var registrationType = '';
var selectedPlan = null;
var selectedLevel = '';
var hasReport = false;
/* ============================================================
STEP DISPLAY + PROGRESS BAR
============================================================ */
function getRoute() {
return ROUTES[registrationType] || ROUTES['New Registration'];
}
function showStep(domStepId) {
currentDomStep = domStepId;
ALL_DOM_STEPS.forEach(function (id) {
var el = document.getElementById('fx-step-' + id);
if (el) el.style.display = (id === domStepId) ? 'block' : 'none';
});
updateProgress(domStepId);
window.scrollTo({ top: 0, behavior: 'smooth' });
}
function updateProgress(domStepId) {
var route = getRoute();
var pos = route.steps.indexOf(domStepId);
if (pos < 0) pos = 0;
var humanPos = pos + 1;
var total = route.total;
var pct = (humanPos / total) * 100;
var fill = document.getElementById('fx-progress-fill');
var text = document.getElementById('fx-progress-text');
if (fill) fill.style.width = pct + '%';
if (text) text.textContent = 'Step ' + humanPos + ' of ' + total;
}
function goNext() {
var route = getRoute();
var pos = route.steps.indexOf(currentDomStep);
if (pos 0) showStep(route.steps[pos - 1]);
}
/* ============================================================
REGISTRATION TYPE CARDS
============================================================ */
document.querySelectorAll('input[name="registration-type"]').forEach(function (radio) {
radio.addEventListener('change', function () {
registrationType = this.value;
document.getElementById('fx-reg-type').value = registrationType;
var planSection = document.getElementById('fx-plan-section');
var sessionSection = document.getElementById('fx-session-section');
if (planSection) planSection.style.display = 'block';
if (selectedPlan && sessionSection) sessionSection.style.display = 'block';
/* Lookup is triggered manually by the user via the
"Look Up My Records" button on Step 2.5 */
});
});
/* ============================================================
PLAN CARDS
Update plan names and pricing as directed by management
============================================================ */
var PLANS = {
'Single Session': { sessions: 1, price: 'RM 30' },
'Bundle (3 Sessions)': { sessions: 3, price: 'RM 75' },
'Group Bundle': { sessions: 3, price: 'RM 300' }
};
document.querySelectorAll('input[name="plan-selection"]').forEach(function (radio) {
radio.addEventListener('change', function () {
selectedPlan = this.value;
document.getElementById('fx-selected-plan').value = selectedPlan;
var plan = PLANS[selectedPlan];
if (plan) {
document.getElementById('fx-session-count').value = plan.sessions;
buildDatePickers(plan.sessions);
var ss = document.getElementById('fx-session-section');
if (ss) ss.style.display = 'block';
updatePaymentSummary();
}
});
});
/* ============================================================
DATE PICKERS
AMEND according to programme calendar provided by
Team Lead / Supervisor / Manager.
============================================================ */
function buildDatePickers(count) {
var wrapper = document.getElementById('fx-dates-wrapper');
if (!wrapper) return;
wrapper.innerHTML = '';
for (var i = 0; i < count; i++) {
var lbl = count === 1 ? 'Session Date' : ordinalLabel(i + 1) + ' Session Date';
var fieldName = 'session-date-' + (i + 1);
var wrap = document.createElement('div');
wrap.className = 'fx-date-picker-wrap';
wrap.innerHTML =
'
' +
'';
wrapper.appendChild(wrap);
}
}
function ordinalLabel(n) {
var sfx = ['th','st','nd','rd'];
var v = n % 100;
return n + (sfx[(v - 20) % 10] || sfx[v] || sfx[0]);
}
/* ============================================================
RETURNING REGISTRATION — REAL FETCH LOGIC
Calls the WPCode PHP snippet via wp_ajax endpoint.
Nonce is injected by PHP into window.c2rAjax automatically.
============================================================ */
/* Internal state for sibling flow */
var returningEmail = '';
function initiateReturningLookup() {
/* Read email from the returning email input field
(injected into Step 2.5 HTML — see fx-ret-email-wrap) */
var emailInput = document.getElementById('fx-ret-email-input');
if (!emailInput || !emailInput.value.trim()) {
showReturningError('Please enter your email address to look up your records.');
return;
}
var email = emailInput.value.trim();
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
showReturningError('Please enter a valid email address.');
return;
}
returningEmail = email;
hideReturningError();
showReturningLoading(true);
/* Check c2rAjax is available (WPCode snippet must be active) */
if (typeof window.c2rAjax === 'undefined') {
showReturningLoading(false);
showReturningError('Lookup service is not available. Please contact us directly at hello@care2run.my.');
return;
}
fetch(window.c2rAjax.ajaxurl, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
action: 'c2r_returning_user_lookup',
nonce: window.c2rAjax.nonce,
email: email
})
})
.then(function (r) { return r.json(); })
.then(function (res) {
showReturningLoading(false);
if (!res.success) {
/* rate_limited, nonce fail, server error */
var msg = (res.data && res.data.message)
? res.data.message
: 'An unexpected error occurred. Please try again or contact us at hello@care2run.my.';
showReturningError(msg);
return;
}
var payload = res.data;
if (payload.state === 'multiple') {
/* Siblings found — show dropdown for selection */
showSiblingDropdown(payload.siblings, payload.message);
} else if (payload.state === 'full') {
applyReturningState('full', payload.data);
} else if (payload.state === 'partial') {
applyReturningState('partial', payload.data);
} else {
/* not_found */
applyReturningState('not_found', {});
}
})
.catch(function () {
showReturningLoading(false);
showReturningError('Could not connect to the lookup service. Please check your internet connection and try again.');
});
}
/* Called when user selects a child from the sibling dropdown */
function fetchByEntryId(entryId) {
showReturningLoading(true);
hideSiblingDropdown();
fetch(window.c2rAjax.ajaxurl, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
action: 'c2r_returning_user_fetch',
nonce: window.c2rAjax.nonce,
entry_id: entryId
})
})
.then(function (r) { return r.json(); })
.then(function (res) {
showReturningLoading(false);
if (!res.success) {
var msg = (res.data && res.data.message) ? res.data.message : 'Could not retrieve this record.';
showReturningError(msg);
return;
}
var payload = res.data;
if (payload.state === 'full') applyReturningState('full', payload.data);
else if (payload.state === 'partial') applyReturningState('partial', payload.data);
else applyReturningState('not_found', {});
})
.catch(function () {
showReturningLoading(false);
showReturningError('Could not retrieve this record. Please try again.');
});
}
/* Populate blue or yellow panel with retrieved data */
function applyReturningState(state, data) {
var blue = document.getElementById('fx-ret-blue');
var yellow = document.getElementById('fx-ret-yellow');
var red = document.getElementById('fx-ret-red');
if (blue) blue.style.display = 'none';
if (yellow) yellow.style.display = 'none';
if (red) red.style.display = 'none';
hideSiblingDropdown();
function val(v) { return (v && v.trim()) ? v.trim() : '—'; }
if (state === 'full') {
if (blue) {
blue.style.display = 'block';
document.getElementById('ret-participant-name').textContent = val(data.participant_name);
document.getElementById('ret-contact').textContent = val(data.contact);
document.getElementById('ret-age').textContent = val(data.age);
document.getElementById('ret-parent-name').textContent = val(data.parent_name);
document.getElementById('ret-parent-contact').textContent = val(data.parent_contact);
document.getElementById('ret-parent-email').textContent = val(data.parent_email);
document.getElementById('ret-emergency-name').textContent = val(data.emergency_name);
document.getElementById('ret-emergency-contact').textContent = val(data.emergency_contact);
document.getElementById('ret-emergency-email').textContent = val(data.emergency_email);
}
} else if (state === 'partial') {
if (yellow) {
yellow.style.display = 'block';
document.getElementById('ret-p-participant-name').textContent = val(data.participant_name);
document.getElementById('ret-p-contact').textContent = val(data.contact);
document.getElementById('ret-p-age').textContent = val(data.age);
document.getElementById('ret-p-parent-name').textContent = val(data.parent_name);
document.getElementById('ret-p-parent-contact').textContent = val(data.parent_contact);
document.getElementById('ret-p-parent-email').textContent = val(data.parent_email);
document.getElementById('ret-p-emergency-name').textContent = val(data.emergency_name);
document.getElementById('ret-p-emergency-contact').textContent = val(data.emergency_contact);
document.getElementById('ret-p-emergency-email').textContent = val(data.emergency_email);
}
} else {
/* not_found */
if (red) red.style.display = 'block';
}
}
/* Show inline sibling selection dropdown */
function showSiblingDropdown(siblings, message) {
var box = document.getElementById('fx-ret-sibling-box');
if (!box) return;
var html = '
' +
(message || 'We found more than one registration under this email. Please select the child you are registering for.') +
'
' +
'' +
'-- Select a child --';
siblings.forEach(function (s) {
html += '' +
s.child_name + ' (submitted ' + s.submitted + ')' +
'';
});
html += '' +
'
';
box.innerHTML = html;
box.style.display = 'block';
document.getElementById('fx-ret-sibling-btn').addEventListener('click', function () {
var sel = document.getElementById('fx-ret-sibling-select');
if (!sel || !sel.value) {
showReturningError('Please select a child from the list first.');
return;
}
fetchByEntryId(parseInt(sel.value, 10));
});
}
function hideSiblingDropdown() {
var box = document.getElementById('fx-ret-sibling-box');
if (box) { box.innerHTML = ''; box.style.display = 'none'; }
}
/* Loading spinner shown during fetch */
function showReturningLoading(show) {
var loader = document.getElementById('fx-ret-loading');
if (loader) loader.style.display = show ? 'block' : 'none';
}
/* Inline error message within the returning panel */
function showReturningError(msg) {
var err = document.getElementById('fx-ret-error');
if (err) { err.textContent = '⚠️ ' + msg; err.style.display = 'block'; }
}
function hideReturningError() {
var err = document.getElementById('fx-ret-error');
if (err) err.style.display = 'none';
}
/* Wire the Look Up button in Step 2.5 */
var lookupBtn = document.getElementById('fx-ret-lookup-btn');
if (lookupBtn) {
lookupBtn.addEventListener('click', function () { initiateReturningLookup(); });
}
/* Also allow Enter key in email field to trigger lookup */
var emailInput = document.getElementById('fx-ret-email-input');
if (emailInput) {
emailInput.addEventListener('keydown', function (e) {
if (e.key === 'Enter') { e.preventDefault(); initiateReturningLookup(); }
});
}
/* ============================================================
PAYMENT SUMMARY
============================================================ */
function updatePaymentSummary() {
var display = document.getElementById('fx-payment-plan-display');
if (!display || !selectedPlan) return;
var plan = PLANS[selectedPlan];
if (!plan) return;
display.innerHTML =
'
' + selectedPlan + ' — ' +
plan.sessions + ' session(s) —
' + plan.price + '';
}
/* ============================================================
PAYMENT METHOD TOGGLE
============================================================ */
document.querySelectorAll('input[name="payment-method"]').forEach(function (radio) {
radio.addEventListener('change', function () {
var qr = document.getElementById('fx-qr-area');
var bk = document.getElementById('fx-bank-area');
if (this.value === 'QR Code') {
if (qr) qr.style.display = 'block';
if (bk) bk.style.display = 'none';
} else {
if (qr) qr.style.display = 'none';
if (bk) bk.style.display = 'block';
}
});
});
/* ============================================================
SECTION B — REPORT TOGGLE + L1/L2/L3 BRANCHING
============================================================ */
function setupReportToggle() {
document.querySelectorAll('input[name="has-report"]').forEach(function (r) {
r.addEventListener('change', handleReportChange);
});
}
function handleReportChange() {
var checked = document.querySelector('input[name="has-report"]:checked');
var uploadBox = document.getElementById('fx-report-upload-box');
var levelSec = document.getElementById('fx-support-level-section');
var l1 = document.getElementById('fx-step-b-l1');
var l23 = document.getElementById('fx-step-b-l23');
if (!checked) return;
hasReport = checked.value.indexOf('Yes') === 0;
if (uploadBox) uploadBox.style.display = hasReport ? 'block' : 'none';
if (levelSec) levelSec.style.display = hasReport ? 'none' : 'block';
if (hasReport) {
if (l1) l1.style.display = 'none';
if (l23) l23.style.display = 'none';
toggleLevelFields('');
} else {
handleLevelChange();
}
}
function handleLevelChange() {
var l1 = document.getElementById('fx-step-b-l1');
var l23 = document.getElementById('fx-step-b-l23');
if (selectedLevel === 'L1') {
if (l1) l1.style.display = 'block';
if (l23) l23.style.display = 'none';
toggleLevelFields('L1');
} else if (selectedLevel === 'L2' || selectedLevel === 'L3') {
if (l1) l1.style.display = 'none';
if (l23) l23.style.display = 'block';
toggleLevelFields('L23');
} else {
if (l1) l1.style.display = 'none';
if (l23) l23.style.display = 'none';
toggleLevelFields('');
}
}
function toggleLevelFields(active) {
var l1Fields = document.querySelectorAll('#fx-step-b-l1 input, #fx-step-b-l1 textarea, #fx-step-b-l1 select');
var l23Fields = document.querySelectorAll('#fx-step-b-l23 input, #fx-step-b-l23 textarea, #fx-step-b-l23 select');
l1Fields.forEach(function (el) { el.disabled = (active !== 'L1'); });
l23Fields.forEach(function (el) { el.disabled = (active !== 'L23'); });
}
document.querySelectorAll('input[name="support-level"]').forEach(function (radio) {
radio.addEventListener('change', function () {
selectedLevel = this.value;
document.getElementById('fx-support-level').value = selectedLevel;
handleLevelChange();
});
});
setupReportToggle();
/* ============================================================
OTHERS TOGGLE HELPERS
============================================================ */
function setupOthersToggle(checkboxName, boxId) {
var els = document.querySelectorAll('[name="' + checkboxName + '[]"], [name="' + checkboxName + '"]');
function check() {
var found = false;
els.forEach(function (cb) { if (cb.value && cb.value.trim() === 'Others' && cb.checked) found = true; });
var box = document.getElementById(boxId);
if (box) box.style.display = found ? 'block' : 'none';
}
els.forEach(function (cb) { cb.addEventListener('change', check); });
check();
}
setupOthersToggle('l1-diagnosed', 'l1-diagnosed-other-box');
setupOthersToggle('l1-traits', 'l1-traits-other-box');
setupOthersToggle('l1-comm-mode', 'l1-comm-other-box');
setupOthersToggle('l1-motivation', 'l1-motivation-other-box');
setupOthersToggle('l23-diagnosed', 'l23-diagnosed-other-box');
setupOthersToggle('l23-traits', 'l23-traits-other-box');
setupOthersToggle('l23-comm-mode', 'l23-comm-other-box');
setupOthersToggle('l23-comm-aids', 'l23-comm-aids-other-box');
setupOthersToggle('l23-motivation', 'l23-motivation-other-box');
setupOthersToggle('hear-about', 'hear-about-other-box');
setupOthersToggle('connect-future', 'connect-future-other-box');
/* ============================================================
FIELD ERROR HELPERS
============================================================ */
function showErr(id, show) {
var el = document.getElementById(id);
if (el) el.style.display = show ? 'block' : 'none';
}
function scrollToFirstError() {
var first = document.querySelector('.fx-field-error[style*="block"], .fx-error[style*="block"]');
if (first) first.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
/* ============================================================
VALIDATION — STEP 0
============================================================ */
function validateStep0() {
var ok = true;
var regType = document.querySelector('input[name="registration-type"]:checked');
showErr('err-reg-type', !regType);
if (!regType) ok = false;
var plan = document.querySelector('input[name="plan-selection"]:checked');
showErr('err-plan', !plan);
if (!plan) ok = false;
var firstDate = document.getElementById('session-date-1');
var dateEmpty = !firstDate || !firstDate.value;
showErr('err-session-date', dateEmpty);
if (dateEmpty) ok = false;
return ok;
}
/* ============================================================
VALIDATION — STEP 1 (Section A)
============================================================ */
function validateStep1() {
var ok = true;
var fields = [
['child-fullname', 'err-child-fullname'],
['child-nickname', 'err-child-nickname'],
['child-dob', 'err-child-dob'],
['child-age', 'err-child-age'],
['mother-fullname', 'err-mother-fullname'],
['mother-nickname', 'err-mother-nickname'],
['mother-email', 'err-mother-email'],
['mother-mobile', 'err-mother-mobile'],
['mother-ic', 'err-mother-ic'],
['emergency-name', 'err-emergency-name'],
['emergency-mobile', 'err-emergency-mobile'],
['emergency-email', 'err-emergency-email']
];
fields.forEach(function (f) {
var el = document.querySelector('[name="' + f[0] + '"]');
var empty = !el || !el.value.trim();
showErr(f[1], empty);
if (empty) ok = false;
});
var gender = document.querySelector('input[name="child-gender"]:checked');
showErr('err-child-gender', !gender);
if (!gender) ok = false;
var nat = document.querySelector('select[name="child-nationality"]');
showErr('err-child-nationality', !nat || !nat.value);
if (!nat || !nat.value) ok = false;
var kt = document.querySelector('select[name="kids-tshirt"]');
showErr('err-kids-tshirt', !kt || !kt.value);
if (!kt || !kt.value) ok = false;
var mt = document.querySelector('select[name="mother-tshirt"]');
showErr('err-mother-tshirt', !mt || !mt.value);
if (!mt || !mt.value) ok = false;
var ma = document.querySelector('input[name="mother-accompany"]:checked');
showErr('err-mother-accompany', !ma);
if (!ma) ok = false;
return ok;
}
/* ============================================================
VALIDATION — STEP 2 (Section B)
============================================================ */
function validateStep2() {
var ok = true;
var fs = document.querySelector('[name="favourite-sports"]');
showErr('err-favourite-sports', !fs || !fs.value.trim());
if (!fs || !fs.value.trim()) ok = false;
var al = document.querySelector('select[name="activity-level"]');
showErr('err-activity-level', !al || !al.value);
if (!al || !al.value) ok = false;
var gi = document.querySelector('select[name="guardian-involvement"]');
showErr('err-guardian-involvement', !gi || !gi.value);
if (!gi || !gi.value) ok = false;
var rep = document.querySelector('input[name="has-report"]:checked');
var repInvalid = !rep;
showErr('err-has-report', repInvalid);
if (repInvalid) {
ok = false;
} else if (!hasReport && !selectedLevel) {
showErr('err-support-level', true);
ok = false;
} else {
showErr('err-support-level', false);
}
return ok;
}
/* ============================================================
VALIDATION — STEP 2.5 (Returning Review)
Blocks if red state — user must go back.
============================================================ */
function validateStep25() {
var blue = document.getElementById('fx-ret-blue');
var yellow = document.getElementById('fx-ret-yellow');
var red = document.getElementById('fx-ret-red');
var siblingBox = document.getElementById('fx-ret-sibling-box');
var errBox = document.getElementById('fx-ret-step25-error');
function showStep25Err(msg) {
if (errBox) { errBox.textContent = '⚠️ ' + msg; errBox.style.display = 'block'; }
}
function hideStep25Err() {
if (errBox) errBox.style.display = 'none';
}
// Check 1: User has not clicked Look Up at all
// None of the panels are visible and sibling box is empty
var blueVisible = blue && blue.style.display !== 'none';
var yellowVisible = yellow && yellow.style.display !== 'none';
var redVisible = red && red.style.display !== 'none';
var siblingVisible = siblingBox && siblingBox.style.display !== 'none'
&& siblingBox.innerHTML.trim() !== '';
if (!blueVisible && !yellowVisible && !redVisible && !siblingVisible) {
showStep25Err('Please enter your email address and click "Look Up My Records" before continuing.');
return false;
}
// Check 2: Red panel — no data found, must go back
if (redVisible) {
showStep25Err('No records were found. Please click Previous and select New Registration.');
return false;
}
// Check 3: Sibling dropdown is still showing — user has not picked a child yet
if (siblingVisible) {
var sel = document.getElementById('fx-ret-sibling-select');
if (!sel || !sel.value || sel.value === '') {
showStep25Err('We found more than one registration. Please select which child you are registering for before continuing.');
return false;
}
}
// Check 4: Yellow panel — warn but allow to proceed
// (user may choose to continue with partial data)
hideStep25Err();
return true;
}
/* ============================================================
VALIDATION — STEP 3 (Policies)
============================================================ */
function validateStep3() {
var policies = [
['policy-health', 'err-policy-health'],
['policy-emergency', 'err-policy-emergency'],
['policy-accompany', 'err-policy-accompany'],
['policy-fees', 'err-policy-fees'],
['policy-photos', 'err-policy-photos'],
['policy-indemnity', 'err-policy-indemnity']
];
var ok = true;
policies.forEach(function (p) {
var cb = document.querySelector('input[name="' + p[0] + '"]');
showErr(p[1], !cb || !cb.checked);
if (!cb || !cb.checked) ok = false;
});
return ok;
}
/* ============================================================
VALIDATION — STEP 4 (Payment + Stay Connected)
============================================================ */
function validateStep4() {
var ok = true;
var hear = document.querySelectorAll('input[name="hear-about[]"]:checked, input[name="hear-about"]:checked');
showErr('err-hear-about', hear.length === 0);
if (hear.length === 0) ok = false;
var conn = document.querySelectorAll('input[name="connect-future[]"]:checked, input[name="connect-future"]:checked');
showErr('err-connect-future', conn.length === 0);
if (conn.length === 0) ok = false;
var uploaded = document.querySelector('.dnd-upload-status.complete, .codedropz-upload-status.complete');
showErr('err-payment-slip', !uploaded);
if (!uploaded) ok = false;
return ok;
}
/* ============================================================
NEXT / PREV BUTTON WIRING
============================================================ */
document.querySelectorAll('.fx-btn-next').forEach(function (btn) {
btn.addEventListener('click', function () {
var validates = this.getAttribute('data-validates');
var passed = true;
if (validates === 'step0') passed = validateStep0();
else if (validates === 'step1') passed = validateStep1();
else if (validates === 'step2') passed = validateStep2();
else if (validates === 'step25') passed = validateStep25();
else if (validates === 'step3') passed = validateStep3();
if (!passed) { scrollToFirstError(); return; }
goNext();
});
});
document.querySelectorAll('.fx-btn-prev').forEach(function (btn) {
btn.addEventListener('click', function () { goPrev(); });
});
/* ============================================================
CF7 SUBMIT GUARD
All Step 1 and Step 2 fields use plain CF7 shortcodes
(no * asterisk) so CF7 does not natively validate them.
Our JS validators handle all required field checks instead.
This guard only blocks submission if our Step 4 JS check
fails (payment upload or stay-connected fields missing).
============================================================ */
var cf7Form = document.querySelector('.wpcf7-form');
if (cf7Form) {
cf7Form.addEventListener('submit', function (e) {
if (!validateStep4()) {
e.preventDefault();
e.stopPropagation();
scrollToFirstError();
}
}, true);
}
document.addEventListener('wpcf7invalid', function (e) {
var box = document.getElementById('fx-cf7-error');
if (!box || !e.detail || !e.detail.apiResponse) return;
var invalid = (e.detail.apiResponse.invalid_fields || []);
if (!invalid.length) return;
var msgs = invalid.map(function (f) { return f.message || f.field; }).join(', ');
box.textContent = '⚠️ Please fix the following before submitting: ' + msgs;
box.style.display = 'block';
box.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, false);
document.addEventListener('wpcf7submit', function () {
var box = document.getElementById('fx-cf7-error');
if (box) box.style.display = 'none';
}, false);
/* ============================================================
INITIALISE
============================================================ */
toggleLevelFields('');
showStep(0);
});