v0.1

ModalsUX
#91 - Hide Popup For Set Duration
Hide a popup for X time when a button is clicked.
Watch the video for step-by-step implementation instructions
<!-- 💙 MEMBERSCRIPT #225 v0.1 💙 FORCE PASSWORD CHANGE AFTER X DAYS -->
<script>
document.addEventListener("DOMContentLoaded", async function() {
var CONFIG = {
maxAgeDays: 90,
snoozeDays: 1,
maxSnoozes: 3,
jsonKey: "password_policy",
modalDisplay: "flex",
allowSnooze: true
};
var memberstack = window.$memberstackDom;
if (!memberstack) {
console.warn("Memberscript # number225: Memberstack not found");
return;
}
// ─── GET MEMBER ───
var member;
try {
var memberResult = await memberstack.getCurrentMember();
member = memberResult?.data || memberResult;
} catch (err) {
console.warn("Memberscript # number225: Could not get member", err);
return;
}
if (!member || !member.id) return;
var memberJSON = {};
try {
var jsonResult = await memberstack.getMemberJSON();
memberJSON = jsonResult?.data || {};
} catch (e) {}
// ─── DOM REFERENCES ───
var modal = document.querySelector('[data-ms-pwexpiry="modal"]');
if (!modal) return;
var maxAgeDays = parseInt(modal.getAttribute("ms-pwexpiry-days")) || CONFIG.maxAgeDays;
var snoozeDays = parseInt(modal.getAttribute("ms-pwexpiry-snooze-days")) || CONFIG.snoozeDays;
var maxSnoozes = parseInt(modal.getAttribute("ms-pwexpiry-max-snoozes")) || CONFIG.maxSnoozes;
var jsonKey = modal.getAttribute("ms-pwexpiry-field") || CONFIG.jsonKey;
var modalDisplay = modal.getAttribute("ms-pwexpiry-display") || CONFIG.modalDisplay;
var allowSnooze = modal.getAttribute("ms-pwexpiry-allow-snooze");
allowSnooze = allowSnooze !== null ? allowSnooze !== " keywordfalse" : CONFIG.allowSnooze;
var daysExpiredEl = document.querySelector('[data-ms-pwexpiry="days-expired"]');
var lastChangedEl = document.querySelector('[data-ms-pwexpiry="last-changed"]');
var maxAgeDaysEl = document.querySelector('[data-ms-pwexpiry="max-age-days"]');
var snoozeCountEl = document.querySelector('[data-ms-pwexpiry="snoozes-remaining"]');
var changePwBtn = document.querySelectorAll('[data-ms-pwexpiry="change-password"]');
var snoozeBtns = document.querySelectorAll('[data-ms-pwexpiry="snooze"]');
var successView = modal.querySelector('[data-ms-pwexpiry="success"]');
modal.style.display = "none";
if (successView) successView.style.display = "none";
// ─── TRACKING HELPERS ───
function getTracking() {
var d = memberJSON[jsonKey];
if (!d || typeof d !== "object") {
return { last_changed: null, snooze_until: null, snooze_count: 0 };
}
return d;
}
async function saveTracking(data) {
memberJSON[jsonKey] = data;
try {
await memberstack.updateMemberJSON({ json: memberJSON });
} catch (e) {
console.warn("Memberscript # number225: Could not save tracking data", e);
}
}
function daysBetween(dateA, dateB) {
return Math.floor((dateB - dateA) / 86400000);
}
function formatDate(isoStr) {
var d = new Date(isoStr);
var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
return months[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear();
}
// ─── SHOW MODAL ───
function showModal(tracking) {
var daysSince = daysBetween(new Date(tracking.last_changed), new Date());
var snoozesLeft = Math.max(0, maxSnoozes - (tracking.snooze_count || 0));
var canSnooze = allowSnooze && snoozesLeft > 0;
if (daysExpiredEl) daysExpiredEl.textContent = daysSince;
if (lastChangedEl) lastChangedEl.textContent = formatDate(tracking.last_changed);
if (maxAgeDaysEl) maxAgeDaysEl.textContent = maxAgeDays;
if (snoozeCountEl) snoozeCountEl.textContent = snoozesLeft;
snoozeBtns.forEach(function(btn) {
btn.style.display = canSnooze ? "" : "none";
});
modal.style.display = modalDisplay;
}
// ─── PASSWORD CHANGED ───
async function markPasswordChanged(tracking) {
tracking.last_changed = new Date().toISOString();
tracking.snooze_until = null;
tracking.snooze_count = 0;
await saveTracking(tracking);
if (successView) {
successView.style.display = "";
setTimeout(function() {
modal.style.display = "none";
if (successView) successView.style.display = "none";
}, 3000);
} else {
modal.style.display = "none";
}
}
// ─── SNOOZE ───
async function snooze(tracking) {
tracking.snooze_count = (tracking.snooze_count || 0) + 1;
var until = new Date();
until.setDate(until.getDate() + snoozeDays);
tracking.snooze_until = until.toISOString();
await saveTracking(tracking);
modal.style.display = "none";
}
// ─── MAIN LOGIC ───
var tracking = getTracking();
var now = new Date();
if (!tracking.last_changed) {
tracking.last_changed = now.toISOString();
tracking.snooze_count = 0;
await saveTracking(tracking);
return;
}
var lastChangedDate = new Date(tracking.last_changed);
var daysSinceChange = daysBetween(lastChangedDate, now);
if (daysSinceChange < maxAgeDays) return;
if (tracking.snooze_until) {
var snoozeExpiry = new Date(tracking.snooze_until);
if (now < snoozeExpiry) return;
}
showModal(tracking);
// ─── EVENT HANDLERS ───
changePwBtn.forEach(function(btn) {
btn.addEventListener("click", async function(e) {
e.preventDefault();
try {
await memberstack.openModal("PROFILE", { defaultTab: "security" });
await markPasswordChanged(tracking);
} catch (err) {
console.warn("Memberscript # number225: Could not open profile modal", err);
}
});
});
snoozeBtns.forEach(function(btn) {
btn.addEventListener("click", function(e) {
e.preventDefault();
snooze(tracking);
});
});
});
</script>More scripts in JSON