Brand Help DocsForms & Dashboards

How to support creator SSO from the Superfiliate portal

Use this HTML/body

<div style="
box-sizing: border-box;
width: 100%;
max-width: 100%;
margin: 0;
padding: 0;
font-family: Avenir;
font-style: normal;
font-weight: 300;
color: #fff;
line-height: 1;
overflow: visible;
">
<span id="sf-email" style="display:none;">{{sf_email}}</span>

<div id="sf-campaign-wrapper">
  <section data-tier="practitioner" class="tier-section">
    <!-- Your existing tier card HTML here -->
    <div style="background: url('https://cdn.shopify.com/s/files/1/0405/7291/1765/files/Practiitoner.png?v=1760349949') #D9D9D9 25% 30%/ cover no-repeat; border-radius: 17px; padding: 15px; min-height: 80px; display: flex; align-items: center; justify-content: space-between; width: 100%; box-sizing: border-box;">
      <div style="font-size: 50px; font-weight: 300; letter-spacing: -1.9px; text-align: left;">Practitioner</div>
    </div>
  </section>
</div>
</div>

and this JS

(function () {
  'use strict';

  /* ========= CONFIG ========= */
  const INIT_DELAY = 320;
  const STYLE_ID = 'cc-storefront-button-v1';
  const STOREFRONT_LABEL = 'Click here to edit your storefront';
  const SSO_API_URL = 'https://creatorcommerce.retool.com/url/cc-superfiliate-sso'; // ✅ UPDATED ENDPOINT
  const DEBUG = true;

  const log = (...a) => { if (DEBUG) console.log('[CC-Storefront]', ...a); };
  const warn = (...a) => { if (DEBUG) console.warn('[CC-Storefront]', ...a); };
  const err = (...a) => { if (DEBUG) console.error('[CC-Storefront]', ...a); };

  const isLocalhost = /localhost|127\.0\.0\.1|\[::1\]/.test(location.hostname);
  if (!location.pathname.includes('/portal') && !isLocalhost) return;

  /* ========= STYLES ========= */
  function injectStyles() {
    log('🎨 Injecting styles...');
    let s = document.getElementById(STYLE_ID);
    if (!s) {
      s = document.createElement('style');
      s.id = STYLE_ID;
      document.head.appendChild(s);
    }
    s.textContent = `
.cc-storefront-container {
  margin-top: 16px;
}

.cc-storefront-button {
  position: relative;
  display: block !important;
  width: 100%;
  min-height: 48px !important;
  border: 0 !important;
  border-radius: 14px !important;
  overflow: hidden;
  cursor: pointer;
  background: #FF4438 !important;
  color: #fff !important;
  box-shadow: 0 6px 22px rgba(255,68,56,.35);
  transition: transform .2s ease, box-shadow .2s ease;
  user-select: none;
  outline: none;
}

.cc-storefront-button:hover {
  transform: translateY(-1px) scale(1.01);
  box-shadow: 0 12px 30px rgba(255,68,56,.48);
}

.cc-storefront-layer {
  position: relative;
  z-index: 3;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  padding: 12px 16px;
}

.cc-storefront-label {
  font-family: 'Avenir', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: .3px;
  text-align: center;
  color: #fff;
}

/* Theme variants */
.cc-storefront-button.tier-rise {
  background: linear-gradient(90deg, #F97644 8%, #EA3507 91.77%) !important;
  box-shadow: 0 6px 22px rgba(234,53,7,.35);
}
.cc-storefront-button.tier-rise:hover {
  box-shadow: 0 12px 30px rgba(234,53,7,.48);
}

.cc-storefront-button.tier-radiate {
  background: linear-gradient(90deg, #EDB278 8%, #DA701B 91.77%) !important;
  box-shadow: 0 6px 22px rgba(218,112,27,.35);
}
.cc-storefront-button.tier-radiate:hover {
  box-shadow: 0 12px 30px rgba(218,112,27,.48);
}

.cc-storefront-button.tier-empower {
  background: linear-gradient(90deg, #9BB7DC 8%, #3B77BB 91.77%) !important;
  box-shadow: 0 6px 22px rgba(59,119,187,.35);
}
.cc-storefront-button.tier-empower:hover {
  box-shadow: 0 12px 30px rgba(59,119,187,.48);
}

.cc-storefront-button.tier-vip {
  background: linear-gradient(90deg, #498A6D 8%, #0E4027 91.77%) !important;
  box-shadow: 0 6px 22px rgba(14,64,39,.35);
}
.cc-storefront-button.tier-vip:hover {
  box-shadow: 0 12px 30px rgba(14,64,39,.48);
}

.cc-storefront-button.tier-practitioner {
  background: linear-gradient(90deg, #AAABC0 8%, #6D6C96 91.77%) !important;
  box-shadow: 0 6px 22px rgba(109,108,150,.35);
}
.cc-storefront-button.tier-practitioner:hover {
  box-shadow: 0 12px 30px rgba(109,108,150,.48);
}

@media (max-width: 420px) {
  .cc-storefront-label { font-size: 16px; }
  .cc-storefront-layer { padding: 10px 14px; }
}
`;
    log('✅ Styles injected');
  }

  /* ========= HELPERS ========= */
  function getEmail(wrapper) {
    try {
      const scoped = wrapper?.querySelector?.('#sf-email');
      const el = scoped || document.getElementById('sf-email');
      const text = el?.textContent?.trim() || '';
      if (text) return text;
    } catch (_) {}
    try { if (window.SF_EMAIL) return String(window.SF_EMAIL); } catch (_) {}
    return '';
  }

  function resolveAbsoluteUrl(raw) {
    try {
      if (!raw) return '';
      if (/^https?:\/\//i.test(raw)) return String(raw);
      if (/^\/\//.test(raw)) return location.protocol + raw;
      return new URL(String(raw), location.href).toString();
    } catch (_) { return ''; }
  }

  async function callSSOApi(email) {
    try {
      log('📡 Calling SSO API with email:', email);
      
      const res = await fetch(SSO_API_URL, {
        method: 'POST',
        mode: 'cors',
        cache: 'no-cache',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ email })
      });
      
      if (!res.ok) {
        throw new Error(`HTTP ${res.status}: ${res.statusText}`);
      }
      
      const data = await res.json();
      log('✅ SSO API response:', data);
      
      const targetUrl = data?.link || '';
      
      if (!targetUrl) {
        warn('⚠️ No link returned from SSO API');
        return '';
      }
      
      return resolveAbsoluteUrl(targetUrl);
    } catch (e) {
      err('❌ SSO API failed:', e);
      return '';
    }
  }

  /* ========= BUTTON CREATION ========= */
  function themeStorefrontButton(btn, tier) {
    btn.classList.remove('tier-rise', 'tier-radiate', 'tier-empower', 'tier-practitioner', 'tier-vip');
    const t = tier.toLowerCase();
    if (t === 'empower') btn.classList.add('tier-empower');
    else if (t === 'radiate') btn.classList.add('tier-radiate');
    else if (t === 'practitioner') btn.classList.add('tier-practitioner');
    else if (t === 'vip') btn.classList.add('tier-vip');
    else btn.classList.add('tier-rise');
  }

  function attachStorefrontHandler(btn, wrapper) {
    if (btn.__ccSSO) return;
    
    btn.addEventListener('click', async (e) => {
      e.preventDefault();
      e.stopPropagation();
      if (btn.__ssoLock) return;
      
      const email = getEmail(wrapper);
      if (!email) {
        warn('⚠️ No sf_email found for SSO');
        return;
      }
      
      const WIN_NAME = 'cc_storefront_sso_' + Date.now();
      let pendingWin = null;
      try { pendingWin = window.open('', WIN_NAME); } catch (_) {}
      
      btn.__ssoLock = true;
      const labelEl = btn.querySelector('.cc-storefront-label');
      const prevText = labelEl?.textContent || '';
      
      try {
        if (labelEl) labelEl.textContent = 'Connecting…';
        btn.classList.add('is-loading');
        btn.style.opacity = '0.85';
        btn.disabled = true;
        btn.setAttribute('aria-busy', 'true');
      } catch (_) {}
      
      const target = await callSSOApi(email);
      
      try {
        if (labelEl) labelEl.textContent = prevText;
        btn.classList.remove('is-loading');
        btn.style.opacity = '';
        btn.disabled = false;
        btn.removeAttribute('aria-busy');
      } catch (_) {}
      
      btn.__ssoLock = false;
      
      if (target && /^https?:/i.test(target)) {
        const navigate = () => {
          if (pendingWin) {
            try {
              try { pendingWin.opener = null; } catch (_) {}
              pendingWin.location.replace(target);
              try { pendingWin.focus && pendingWin.focus(); } catch (_) {}
            } catch (_) {
              window.open(target, '_blank', 'noopener,noreferrer');
            }
          } else {
            window.open(target, '_blank', 'noopener,noreferrer');
          }
        };
        setTimeout(navigate, 150);
      } else {
        err('❌ No valid SSO URL returned');
        if (pendingWin) {
          try { pendingWin.close(); } catch (_) {}
        }
      }
    }, { passive: false });
    
    btn.__ccSSO = true;
  }

  function createStorefrontButton(tier) {
    const container = document.createElement('div');
    container.className = 'cc-storefront-container';
    
    const btn = document.createElement('button');
    btn.className = 'cc-storefront-button';
    btn.setAttribute('aria-label', 'Click here to customise your storefront');
    btn.type = 'button';
    
    const layer = document.createElement('div');
    layer.className = 'cc-storefront-layer';
    btn.appendChild(layer);
    
    // ✅ LOGO REMOVED - just label now
    const label = document.createElement('span');
    label.className = 'cc-storefront-label';
    label.textContent = STOREFRONT_LABEL;
    layer.appendChild(label);
    
    themeStorefrontButton(btn, tier);
    container.appendChild(btn);
    
    return { container, btn };
  }

  /* ========= INIT ========= */
  function getTier(section) {
    return section?.getAttribute?.('data-tier') || 'rise';
  }

  function init() {
    log('🚀 Initializing CreatorCommerce storefront button...');
    
    const wrapper = document.getElementById('sf-campaign-wrapper');
    if (!wrapper) {
      warn('⚠️ No #sf-campaign-wrapper found');
      return;
    }
    
    const section = wrapper.querySelector('[data-tier]');
    if (!section) {
      warn('⚠️ No [data-tier] section found');
      return;
    }
    
    const tier = getTier(section);
    log('📍 Detected tier:', tier);
    
    // Check if button already exists
    if (section.querySelector('.cc-storefront-button')) {
      log('✅ Storefront button already exists');
      return;
    }
    
    const { container, btn } = createStorefrontButton(tier);
    section.appendChild(container);
    attachStorefrontHandler(btn, wrapper);
    
    log('✅ Storefront button created and attached');
  }

  function start() {
    injectStyles();
    
    const wrapper = document.getElementById('sf-campaign-wrapper');
    if (wrapper) {
      setTimeout(init, INIT_DELAY);
    } else {
      const observer = new MutationObserver(() => {
        const w = document.getElementById('sf-campaign-wrapper');
        if (w) {
          observer.disconnect();
          setTimeout(init, INIT_DELAY);
        }
      });
      observer.observe(document.body, { childList: true, subtree: true });
    }
  }

  /* ========= BOOT ========= */
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', start, { once: true });
  } else {
    start();
  }
})();

Forms & Dashboards