1/** 2 * Mental Health Assessments â Auto-Save Modal v2.1 3 * 4 * CHANGES FROM v2.0: 5 * - Completely independent modal (MhtModal) â no longer shares or depends on 6 * window.MbtModalShared from the MBTI plugin. Eliminates the bug where 7 * assessment "Get Results" buttons showed the MBTI personality popup. 8 * - RTL / Arabic support built in from the start. 9 * - Uses #mht-assessment-modal (separate from MBTI's #mbt-account-modal). 10 */ 11(function ($) { 12 'use strict'; 13 14 var WEBHOOK_ACCOUNT = 'https://theprivateclinic.me/wp-json/bit-integrations/v1/callback/4136e01d-4106-4c7a-b9d3-56858f6c2787'; 15 16 var TEST_MAP = { 17 phq9: { resultDiv: '#phq9Results', field: 'input[name="phq9-result"]', sevEl: '#phq9Severity' }, 18 gad7: { resultDiv: '#gad7Results', field: 'input[name="gad7-result"]', sevEl: '#gad7Severity' }, 19 asrs: { resultDiv: '#asrsResults', field: 'input[name="asrs-result"]', sevEl: null }, 20 pcptsd: { resultDiv: '#ptsdResults', field: 'input[name="ptsd-result"]', sevEl: null }, 21 'pc-ptsd': { resultDiv: '#ptsdResults', field: 'input[name="ptsd-result"]', sevEl: null }, 22 swed: { resultDiv: '#swedResults', field: 'input[name="swed-result"]', sevEl: null }, 23 epds: { resultDiv: '#epdsResults', field: 'input[name="epds-result"]', sevEl: null }, 24 bpd: { resultDiv: '#bpdResults', field: 'input[name="bpd-result"]', sevEl: null }, 25 spin: { resultDiv: '#spinResults', field: 'input[name="spin-result"]', sevEl: '#spinSeverity' }, 26 }; 27 28 var EMAIL_SEL = [ 29 'input[type="email"]', 30 'input.wpcf7-validates-as-email', 31 'input[name="your-email"]', 32 'input[name*="email"]', 33 ].join(', '); 34 35 /* âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 36 * LOCAL MODAL â completely independent of MBTI plugin. 37 * Uses #mht-assessment-modal so it never conflicts with 38 * MBTI's #mbt-account-modal even when both plugins are active. 39 * âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 40 var MhtModal = (function () { 41 var _cb = null; 42 var _built = false; 43 44 function _isRTL() { 45 return $('html').attr('dir') === 'rtl' || $('body').hasClass('rtl'); 46 } 47 48 function _build() { 49 if (_built || $('#mht-assessment-modal').length) { _built = true; return; } 50 _built = true; 51 52 var rtl = _isRTL(); 53 var closePos = rtl ? 'left:14px;right:auto;' : 'right:14px;left:auto;'; 54 var dirStyle = rtl ? 'direction:rtl;text-align:right;' : ''; 55 var arrowChar = rtl ? '\u2190' : '\u2192'; // â or â 56 57 $('body').append( 58 '<div id="mht-assessment-modal" style="' + 59 'display:none;position:fixed;top:0;left:0;right:0;bottom:0;z-index:999999;' + 60 'background:rgba(15,23,42,.72);align-items:center;justify-content:center;' + 61 'backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);' + 62 'padding:16px;box-sizing:border-box;">' + 63 64 '<div style="' + 65 'background:#fff;border-radius:20px;max-width:420px;width:100%;' + 66 'box-shadow:0 32px 80px rgba(0,0,0,.35);overflow:hidden;position:relative;' + 67 'font-family:-apple-system,BlinkMacSystemFont,\'Segoe UI\',Roboto,sans-serif;' + 68 dirStyle + '">' + 69 70 /* gradient header */ 71 '<div style="background:linear-gradient(135deg,#3d7050 0%,#549263 100%);' + 72 'padding:24px 24px 20px;text-align:center;position:relative;">' + 73 '<button id="mht-modal-close" style="position:absolute;top:12px;' + closePos + 74 'background:rgba(255,255,255,.18);border:none;border-radius:50%;' + 75 'width:30px;height:30px;font-size:18px;
75cursor:pointer;color:#fff;' + 76 'display:flex;align-items:center;justify-content:center;line-height:1;">' + 77 '✕' + 78 '</button>' + 79 '<div style="font-size:38px;margin-bottom:10px;">📊</div>' + 80 '<h3 style="margin:0;font-size:18px;font-weight:700;color:#fff;">' + 81 'Save Your Results' + 82 '</h3>' + 83 '</div>' + 84 85 /* body */ 86 '<div style="padding:22px 24px 0;">' + 87 '<p style="margin:0 0 16px;font-size:15px;font-weight:700;color:#111827;' + 88 'text-align:center;line-height:1.4;">' + 89 'Unlock your free personalised report' + 90 '</p>' + 91 92 '<ul style="list-style:none;margin:0 0 20px;padding:0;' + 93 'display:flex;flex-direction:column;gap:10px;">' + 94 _li('📈', 'Track your mental health over time', 95 'See how you progress across multiple assessments') + 96 _li('🧭', 'Get personalised therapy recommendations', 97 'Matched to your screening results') + 98 _li('🔒', 'Private & secure', 99 'Only you and your care team can see your results') + 100 '</ul>' + 101 102 '<div style="display:flex;flex-direction:column;gap:10px;">' + 103 '<button id="mht-no-account" style="' + 104 'padding:14px 22px;border-radius:12px;font-size:15px;font-weight:700;' + 105 'background:linear-gradient(135deg,#549263,#3d7050);color:#fff;' + 106 'border:none;cursor:pointer;width:100%;' + 107 'box-shadow:0 4px 14px rgba(84,146,99,.45);">' + 108 '✨ Create my free account' + 109 '</button>' + 110 '<button id="mht-has-account" style="' + 111 'padding:12px 22px;border-radius:12px;font-size:14px;font-weight:600;' + 112 'background:#f8faf9;color:#374151;border:1.5px solid #d1d5db;' + 113 'cursor:pointer;width:100%;">' + 114 'I already have an account ' + arrowChar + 115 '</button>' + 116 '</div>' + 117 118 '<p style="margin:14px 0 0;font-size:11px;color:#9ca3af;text-align:center;' + 119 'padding-bottom:20px;">Free forever · No credit card needed</p>' + 120 121 '<p id="mht-modal-msg" style="display:none;margin:10px 0 16px;' + 122 'font-size:13px;font-weight:600;text-align:center;"></p>' + 123 '</div>' + 124 '</div>' + 125 '</div>' 126 ); 127 128 /* hover on primary CTA */ 129 $(document).on('mouseenter', '#mht-no-account', function () { 130 $(this).css({ transform: 'translateY(-2px)', boxShadow: '0 8px 22px rgba(84,146,99,.5)' }); 131 }).on('mouseleave', '#mht-no-account', function () { 132 $(this).css({ transform: '', boxShadow: '0 4px 14px rgba(84,146,99,.45)' }); 133 }); 134 135 $(document).on('click', '#mht-assessment-modal', function (e) { 136 if ($(e.target).is('#mht-assessment-modal')) _hide(); 137 }); 138 $(document).on('click', '#mht-modal-close', _hide); 139 $(document).on('click', '#mht-has-account', function () { 140 var s = _cb; _hide(); if (s) s('existing'); 141 }); 142 $(document).on('click', '#mht-no-account', function () { 143 if (_cb) _cb('new'); 144 }); 145 } 146 147 function _li(icon, title, sub) { 148 return '<li style="display:flex;align-items:flex-start;gap:12px;">' + 149 '<span style="font-size:18px;flex-shrink:0;margin-top:1px;">' + icon + '</span>' + 150 '<span>' + 151 '<strong style="display:block;font-size:13px;font-weight:700;color:#111827;margin-bottom:1px;">' + title + '</strong>' + 152 '<span style="font-size:12px;color:#6b7280;line-height:1.4;">' + sub + '</span>' + 153 '</span>' + 154 '</li>'; 155 } 156 157 function _hide() { 158 $('#mht-assessment-modal').css('display', 'none'); 159 _cb = null; 160 $('#mht-has-account, #mht-no-account').prop('disabled', false); 161 } 162 163 return { 164 show: function (cb) { 165 _build(); 166 _cb = cb; 167 $('#mht-modal-msg').hide().text(''); 168 $('#mht-has-account, #mht-no-account').prop('disabled', false); 169 $('#mht-assessment-modal').css('display', 'flex'); 170 $('html,body').animate({ scrollTop: 0 }, 200); 171 }, 172 hide: _hide, 173 setMsg: function (txt, col) { 174 $('#mht-modal-msg').text(txt).css('color', col || '#549263').show(); 175 }, 176 disableButtons: function () { 177 $('#mht-has-account, #mht-no-account').prop('disabled', true); 178 } 179 }; 180 }()); 181 182 /* âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 183 * HELPERS 184 * âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 185 function findEmail($ctx) { 186 var email = ''; 187 var $els = $ctx ? $ctx.find(EMAIL_SEL).add($(EMAIL_SEL)) : $(EMAIL_SEL); 188 $els.each(function () { 189 var v = $.trim($(this).val()); 190 if (v && v.indexOf('@') > 0) { email = v; return false; } 191 }); 192 return email; 193 } 194 195 function showStatus($div, text, type) { 196 var $s = $div.find('.mht-save-status'); 197 if (!$s.length) { 198 $s = $('<div class="mht-save-status" style="margin-top:16px;padding:12px 16px;' + 199 'border-radius:8px;font-size:14px;font-weight:600;text-align:center;"></div>'); 200 $div.append($s); 201 } 202 var bg, color, border; 203 if (type === 'success') { bg='#f0fdf4'; color='#166534'; border='#bbf7d0'; } 204 else if (type === 'error') { bg='#fef2f2'; color='#991b1b'; border='#fecaca'; } 205 else { bg='#eff6ff'; color='#1e40af'; border='#bfdbfe'; } 206 $s.text(text).css({ background: bg, color: color, border: '1px solid ' + border }).show(); 207 } 208 209 function doSave(key, email, resultText, severity, $div) { 210 showStatus($div, 'Saving your results\u2026', 'info'); 211 $.ajax({ 212 url: (typeof mht_save_data !== 'undefined') ? mht_save_data.ajax_url : '', 213 type: 'POST', 214 data: { 215 action: 'mht_save_to_account', 216 nonce: (typeof mht_save_data !== 'undefined') ? mht_save_data.nonce : '', 217 email: email, 218 test_key: key, 219 result_text: resultText, 220 severity: severity, 221 }, 222 success: function (res) { 223 if (res.success) { 224 showStatus($div, '\u2713 Results saved to your account!', 'success'); 225 } else { 226 showStatus($div, '\u2717 ' + (res.data && res.data.message 227 ? res.data.message : 'Could not save. Please try again.'), 'error'); 228 } 229 }, 230 error: function () { showStatus($div, '\u2717 Network error. Please try again.', 'error'); } 231 }); 232 } 233 234 /* âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 235 * MAIN â intercept CF7 submit inside each [data-test] wrapper 236 * âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ */ 237 $(document).ready(function () { 238 239 $(document).on('submit', '[data-test] .wpcf7-form', function () { 240 var $form = $(this); 241 var $wrapper = $form.closest('[data-test]'); 242 var testKey = $wrapper.data('test'); 243 var cfg = TEST_MAP[testKey]; 244 if (!cfg) return; 245 246 /* Capture email NOW before any field clearing */ 247 var email = findEmail($form); 248 if (!email) { 249 $(EMAIL_SEL).each(function () { 250 var v = $.trim($(this).val()); 251 if (v && v.indexOf('@') > 0) { email = v; return false; } 252 }); 253 } 254 255 /* Test JS runs synchronously â wait one tick for DOM updates */ 256 setTimeout(function () { 257 var $resultDiv = $(cfg.resultDiv); 258 if (!$resultDiv.is(':visible')) return; 259 if ($resultDiv.data('mht-saved')) return; 260 261 var resultText = $form.find(cfg.field).val() || $(cfg.field).val() || ''; 262 var severity = cfg.sevEl ? $.trim($(cfg.sevEl).text()) : ''; 263 264 if (!severity && resultText) { 265 var lines = resultText.split('\n'); 266 for (var i = 0; i < lines.length; i++) { 267 var l = $.trim(lines[i]); 268 if (l && l.indexOf(':') > -1) { 269 severity = $.trim(l.split(':').slice(1).join(':')); 270 break; 271 } 272 } 273 } 274 if (!severity) severity = resultText.substring(0, 80); 275 276 if (!email) { 277 showStatus($resultDiv, 278 '\uD83D\uDCBE Want to save these results? Fill in your email in the form above then click Get Results again.', 279 'info'); 280 return; 281 } 282 283 /* Show the assessment-specific modal (NOT the MBTI modal) */ 284 MhtModal.show(function (choice) { 285 if (choice === 'new') { 286 MhtModal.disableButtons(); 287 MhtModal.setMsg('Creating your account\u2026', '#549263'); 288 $.ajax({ 289 url: WEBHOOK_ACCOUNT, 290 type: 'POST', 291 contentType: 'application/json', 292 data: JSON.stringify({ email: email, source: 'assessment_save', test: testKey }), 293 complete: function () { 294 MhtModal.setMsg('Account created! Saving results\u2026', '#549263'); 295 setTimeout(function () { 296 MhtModal.hide(); 297 $resultDiv.data('mht-saved', true); 298 doSave(testKey, email, resultText, severity, $resultDiv); 299 }, 900); 300 } 301 }); 302 } else { 303 MhtModal.hide(); 304 $resultDiv.data('mht-saved', true); 305 doSave(testKey, email, resultText, severity, $resultDiv); 306 } 307 }); 308 309 }, 80); 310 }); 311 312 }); 313 314})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.