Files
aifo-portal-web/js/landing-welcome-rewards-module.js
T
2026-07-30 18:38:39 +08:00

200 lines
6.5 KiB
JavaScript

/**
* Welcome rewards floor — loads landing-welcome-rewards.section.html
* and fills copy from data-* on the placeholder node.
*
* Placeholder example:
* <div
* data-landing-welcome-rewards
* data-welcome-title-id="dollar-welcome-title"
* data-welcome-title-before="Welcome"
* data-welcome-title-accent="rewards"
* data-welcome-eyebrow="Limited-time offer"
* data-welcome-value="$1"
* data-welcome-sub="ALL CHALLENGES*"
* data-welcome-code-label="Use code"
* data-welcome-code="AIFOPROM"
* data-welcome-cta-text="Claim Now"
* data-welcome-cta-href="#register-now"
* data-welcome-copy-success="Code copied!"
* ></div>
*/
(function () {
var MODULE_URL = '/pages/modules/landing-welcome-rewards.section.html';
var DEFAULT_COPY_SUCCESS = 'Code copied to clipboard!';
var copyToastTimer;
function readConfig(el) {
return {
titleId: el.getAttribute('data-welcome-title-id') || 'landing-welcome-title',
titleBefore: el.getAttribute('data-welcome-title-before') || '',
titleAccent: el.getAttribute('data-welcome-title-accent') || '',
eyebrow: el.getAttribute('data-welcome-eyebrow') || '',
value: el.getAttribute('data-welcome-value') || '',
sub: el.getAttribute('data-welcome-sub') || '',
codeLabel: el.getAttribute('data-welcome-code-label') || '',
code: el.getAttribute('data-welcome-code') || '',
ctaText: el.getAttribute('data-welcome-cta-text') || '',
ctaHref: el.getAttribute('data-welcome-cta-href') || '#register-now',
note: el.getAttribute('data-welcome-note') || '',
copySuccess: el.getAttribute('data-welcome-copy-success') || DEFAULT_COPY_SUCCESS,
};
}
function copyText(text) {
if (!text) return Promise.resolve();
if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
return navigator.clipboard.writeText(text);
}
return new Promise(function (resolve, reject) {
var ta = document.createElement('textarea');
ta.value = text;
ta.setAttribute('readonly', '');
ta.style.position = 'fixed';
ta.style.left = '-9999px';
document.body.appendChild(ta);
ta.select();
try {
if (document.execCommand('copy')) resolve();
else reject(new Error('copy failed'));
} catch (err) {
reject(err);
} finally {
document.body.removeChild(ta);
}
});
}
function getCopyToast() {
var toast = document.getElementById('landing-welcome-copy-toast');
if (toast) return toast;
toast = document.createElement('div');
toast.id = 'landing-welcome-copy-toast';
toast.className = 'landing-welcome-copy-toast';
toast.setAttribute('role', 'status');
toast.setAttribute('aria-live', 'polite');
document.body.appendChild(toast);
return toast;
}
function showCopyToast(message) {
var toast = getCopyToast();
toast.textContent = message;
toast.classList.add('is-visible');
window.clearTimeout(copyToastTimer);
copyToastTimer = window.setTimeout(function () {
toast.classList.remove('is-visible');
}, 2400);
}
function bindPromoCodeCopy(codeEl, config) {
if (!codeEl || !config.code) return;
codeEl.setAttribute('aria-label', 'Copy promo code ' + config.code);
codeEl.addEventListener('click', function () {
copyText(config.code)
.then(function () {
codeEl.classList.add('is-copied');
showCopyToast(config.copySuccess);
window.setTimeout(function () {
codeEl.classList.remove('is-copied');
}, 1200);
})
.catch(function () {
showCopyToast('Copy failed. Please copy manually.');
});
});
}
function setText(node, value) {
if (!node) return;
node.textContent = value;
}
function populateSection(section, config) {
section.setAttribute('aria-labelledby', config.titleId);
var titleEl = section.querySelector('[data-welcome-title]');
if (titleEl) {
titleEl.id = config.titleId;
titleEl.textContent = '';
if (config.titleBefore) {
titleEl.appendChild(document.createTextNode(config.titleBefore));
}
if (config.titleAccent) {
if (config.titleBefore) {
titleEl.appendChild(document.createTextNode(' '));
}
var accent = document.createElement('span');
accent.className = 'landing-accent';
accent.textContent = config.titleAccent;
titleEl.appendChild(accent);
}
}
setText(section.querySelector('[data-welcome-eyebrow]'), config.eyebrow);
setText(section.querySelector('[data-welcome-value]'), config.value);
setText(section.querySelector('[data-welcome-sub]'), config.sub);
var codeWrap = section.querySelector('[data-welcome-code-wrap]');
if (codeWrap && (config.codeLabel || config.code)) {
codeWrap.hidden = false;
setText(section.querySelector('[data-welcome-code-label]'), config.codeLabel);
var codeEl = section.querySelector('[data-welcome-code]');
setText(codeEl, config.code);
bindPromoCodeCopy(codeEl, config);
}
var cta = section.querySelector('[data-welcome-cta]');
if (cta && config.ctaText) {
cta.hidden = false;
cta.textContent = config.ctaText;
cta.href = config.ctaHref;
}
var note = section.querySelector('[data-welcome-note]');
if (note && config.note) {
note.hidden = false;
note.textContent = config.note;
}
}
function loadLandingWelcomeRewardsModule() {
var placeholder = document.querySelector('[data-landing-welcome-rewards]');
if (!placeholder) return;
var config = readConfig(placeholder);
var parent = placeholder.parentNode;
fetch(MODULE_URL, { credentials: 'same-origin' })
.then(function (res) {
if (!res.ok) throw new Error('Failed to load ' + MODULE_URL);
return res.text();
})
.then(function (html) {
var wrap = document.createElement('div');
wrap.innerHTML = html.trim();
var section = wrap.firstElementChild;
if (!section || !parent) return;
populateSection(section, config);
parent.replaceChild(section, placeholder);
document.dispatchEvent(
new CustomEvent('aifo:landing-welcome-rewards-ready', { detail: { config: config } })
);
})
.catch(function (err) {
console.error('[landing-welcome-rewards-module.js]', err);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadLandingWelcomeRewardsModule);
} else {
loadLandingWelcomeRewardsModule();
}
})();