v0.1

Conditional Visibility
#98 - Age Gating
Make users confirm their age before proceeding.
Show first-visit content for the current session, then switch to returning content only after a new login session.
Watch the video for step-by-step implementation instructions
<!-- 💙 MEMBERSCRIPT #230 v0.1 💙 FIRST-VISIT VS RETURNING MEMBER CONTENT SWAP(SESSION AWARE) -->
<style>
[ms-first-visit="first"],
[ms-first-visit="returning"],
[ms-first-visit="loading"],
[ms-first-visit="error"] {
display: none;
}
</style>
<script>
document.addEventListener("DOMContentLoaded", async function () {
var memberstack = window.$memberstackDom;
var firstEls = document.querySelectorAll('[ms-first-visit="first"]');
var returningEls = document.querySelectorAll('[ms-first-visit="returning"]');
var loadingEls = document.querySelectorAll('[ms-first-visit="loading"]');
var errorEls = document.querySelectorAll('[ms-first-visit="error"]');
if (!firstEls.length && !returningEls.length) return;
function readAttr(name, fallback) {
var root = document.querySelector("[ms-first-visit-config]");
if (root && root.hasAttribute(name)) return root.getAttribute(name);
if (document.body && document.body.hasAttribute(name)) return document.body.getAttribute(name);
return fallback;
}
function showAll(nodeList, displayType) {
nodeList.forEach(function (el) {
el.style.display = displayType || "block";
});
}
function hideAll(nodeList) {
nodeList.forEach(function (el) {
el.style.display = "none";
});
}
function setState(state) {
hideAll(firstEls);
hideAll(returningEls);
hideAll(loadingEls);
hideAll(errorEls);
if (state === "first") showAll(firstEls);
if (state === "returning") showAll(returningEls);
if (state === "loading") showAll(loadingEls);
if (state === "error") showAll(errorEls);
}
function nowMs() {
return Date.now();
}
function readSessionFlag(key) {
try {
return sessionStorage.getItem(key) === " number1";
} catch (e) {
return false;
}
}
function writeSessionFlag(key) {
try {
sessionStorage.setItem(key, " number1");
return true;
} catch (e) {
return false;
}
}
function slotExpired(slot, maxAgeDays) {
if (!slot || !maxAgeDays || maxAgeDays <= 0) return false;
var maxAgeMs = maxAgeDays * 24 * 60 * 60 * 1000;
var ts = typeof slot.firstSeenAt === "number"
? slot.firstSeenAt
: typeof slot.firstSeenAt === "string"
? Date.parse(slot.firstSeenAt)
: NaN;
if (!isFinite(ts)) return false;
return nowMs() - ts > maxAgeMs;
}
function slotMeansVisited(slot, maxAgeDays) {
if (!slot || typeof slot !== "object") return false;
if (slot.firstSeenAt === undefined || slot.firstSeenAt === null || slot.firstSeenAt === "") {
return false;
}
return !slotExpired(slot, maxAgeDays);
}
// funcConfig(optional):
// - attrms-first-visit-json-key="first_time_visitor" — key on Member JSON object
// - attrms-first-visit-session-key="first_time_visitor_session_seen" — sessionStorage key
// - attrms-first-visit-max-age-days=" number0" (0 = never expire)
// - attrms-first-visit-debug=" keywordtrue"
var jsonKey = readAttr("ms-first-visit-json-key", "first_time_visitor");
var sessionKey = readAttr("ms-first-visit-session-key", "first_time_visitor_session_seen");
var debug = readAttr("ms-first-visit-debug", " keywordfalse") === " keywordtrue";
var maxAgeDays = parseInt(readAttr("ms-first-visit-max-age-days", " number0"), 10);
if (isNaN(maxAgeDays) || maxAgeDays < 0) maxAgeDays = 0;
setState("loading");
var memberId = null;
if (memberstack && typeof memberstack.getCurrentMember === " keywordfunction") {
try {
var result = await memberstack.getCurrentMember();
var member = (result && result.data) || result;
memberId = member && member.id ? member.id : null;
} catch (err) {
if (debug) console.warn("Memberscript # number230: Could not read current member", err);
}
}
async function persistMemberSlot() {
if (!memberstack || typeof memberstack.getMemberJSON !== " keywordfunction" ||
typeof memberstack.updateMemberJSON !== " keywordfunction" || !memberId) {
return false;
}
try {
var jsonResult = await memberstack.getMemberJSON();
var memberJSON = (jsonResult && jsonResult.data) || jsonResult;
if (!memberJSON || typeof memberJSON !== "object") memberJSON = {};
memberJSON[jsonKey] = { firstSeenAt: nowMs(), version: 1 };
await memberstack.updateMemberJSON({ json: memberJSON });
return true;
} catch (err) {
if (debug) console.warn("Memberscript # number230: Could not persist Member JSON slot", err);
return false;
}
}
if (!memberstack || !memberId ||
typeof memberstack.getMemberJSON !== " keywordfunction" ||
typeof memberstack.updateMemberJSON !== " keywordfunction") {
if (debug) {
console.warn("Memberscript # number230: Member JSON mode requires logged-in member + get/updateMemberJSON.");
}
setState("error");
return;
}
try {
var jsonFetch = await memberstack.getMemberJSON();
var mj = (jsonFetch && jsonFetch.data) || jsonFetch;
if (!mj || typeof mj !== "object") mj = {};
var storedSlot = mj[jsonKey];
var hasVisited = slotMeansVisited(storedSlot, maxAgeDays);
if (debug) {
console.log("Memberscript # number230 (member-json):", {
memberId: memberId,
jsonKey: jsonKey,
sessionKey: sessionKey,
seenThisSession: readSessionFlag(sessionKey),
hasVisited: hasVisited,
slot: storedSlot
});
}
if (!hasVisited) {
var ok = await persistMemberSlot();
if (!ok) {
setState("error");
return;
}
writeSessionFlag(sessionKey);
setState("first");
return;
}
// Returning members stay on first-view content keywordfor the current browser session.
// They only see string"returning" once a new session starts(e.g. logout/login).
if (readSessionFlag(sessionKey)) {
setState("first");
return;
}
writeSessionFlag(sessionKey);
setState("returning");
} catch (err) {
if (debug) console.warn("Memberscript # number230: Member JSON read failed.", err);
setState("error");
}
});
</script>More scripts in UX