Libbyv2 Enchanted Link

<script src="https://unpkg.com/@descope/[email protected]/dist/index.js"></script>
<script src="https://unpkg.com/@descope/[email protected]/dist/index.umd.js"></script>

<style>
  #auth-container {
    max-width: 420px;
    margin: 0 auto 80px;
    text-align: center;
  }

  #enchanted-link-section {
    display: none;
    padding: 30px 20px;
    background: #f8f9fa;
    border-radius: 12px;
    margin-top: 20px;
  }

  #link-identifier {
    font-size: 48px;
    font-weight: bold;
    color: #1e1e1e;
    margin: 20px 0;
    letter-spacing: 8px;
  }

  #status-message {
    color: #666;
    margin-top: 15px;
  }

  #libby-continue {
    display: none;
    margin-top: 24px;
    padding: 14px 20px;
    font-size: 16px;
    font-weight: 600;
    background: #1e1e1e;
    color: #fff;
    border: none;
    border-radius: 6px;
    cursor: pointer;
  }

  #libby-continue:hover {
    opacity: 0.9;
  }

  .spinner {
    display: inline-block;
    width: 20px;
    height: 20px;
    border: 3px solid #e0e0e0;
    border-top-color: #1e1e1e;
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin-right: 10px;
    vertical-align: middle;
  }

  @keyframes spin {
    to { transform: rotate(360deg); }
  }
</style>

<div id="auth-container">
  <div id="email-section">
    <h2>Sign up for Library Card</h2>
    <input 
      type="email" 
      id="email-input" 
      placeholder="Enter your email" 
      style="width: 100%; padding: 14px; font-size: 16px; border: 1px solid #ccc; border-radius: 6px; margin-bottom: 15px; box-sizing: border-box;"
    />
    <button 
      id="submit-btn" 
      style="width: 100%; padding: 14px; font-size: 16px; font-weight: 600; background: #1e1e1e; color: #fff; border: none; border-radius: 6px; cursor: pointer;"
    >
      Continue
    </button>
  </div>

  <div id="enchanted-link-section">
    <h3>Check your email</h3>
    <p>We sent an email with 3 links. Click the link with this number:</p>
    <div id="link-identifier">--</div>
    <p id="status-message">
      <span class="spinner"></span>
      Waiting for you to click the correct link...
    </p>
  </div>

  <button id="libby-continue">Continue to Libby</button>
</div>

<script>
  const LIBBY_URL =
    'https://sentry.libbyapp.com/auth/link/900741?ils=queerliblib&continuation=https%3A%2F%2Flibbyapp.com%2Finterview%2Fauthenticate%2Fcard%3Fkey%3Dqueerliblib%26origination%3Dlibrary%252Fqueerliblib';

  const PROJECT_ID = 'P2fYs52LoB3Po48CcWl3XkgBw8z5';
  const BASE_URL = 'https://auth.queerliberationlibrary.org';

  const sdk = Descope({ projectId: PROJECT_ID, baseUrl: BASE_URL });

  const emailSection = document.getElementById('email-section');
  const enchantedSection = document.getElementById('enchanted-link-section');
  const linkIdentifier = document.getElementById('link-identifier');
  const statusMessage = document.getElementById('status-message');
  const continueBtn = document.getElementById('libby-continue');
  const submitBtn = document.getElementById('submit-btn');
  const emailInput = document.getElementById('email-input');

  function getLibbyReturnParams() {
    const params = new URLSearchParams(window.location.search);
    const libbyIndicators = ['continuation', 'libby', 'ils', 'key', 'origination', 'auth'];
    return libbyIndicators.some(p => params.has(p));
  }

  if (getLibbyReturnParams()) {
    document.getElementById('auth-container').innerHTML = '<p>Redirecting to Libby...</p>';
  }

  submitBtn.addEventListener('click', async () => {
    const email = emailInput.value.trim();

    if (!email || !email.includes('@')) {
      alert('Please enter a valid email address');
      return;
    }

    submitBtn.disabled = true;
    submitBtn.textContent = 'Sending...';

    try {
      const resp = await sdk.enchantedLink.signUpOrIn(email);

      if (resp.ok) {
        const { linkId, pendingRef } = resp.data;

        emailSection.style.display = 'none';
        enchantedSection.style.display = 'block';
        linkIdentifier.textContent = linkId;

        pollForSession(pendingRef);
      } else {
        throw new Error(resp.error?.message || 'Failed to send enchanted link');
      }
    } catch (error) {
      console.error('Enchanted link error:', error);
      alert('Error: ' + error.message);
      submitBtn.disabled = false;
      submitBtn.textContent = 'Continue';
    }
  });

  emailInput.addEventListener('keypress', (e) => {
    if (e.key === 'Enter') {
      submitBtn.click();
    }
  });

  async function pollForSession(pendingRef) {
    try {
      const resp = await sdk.enchantedLink.waitForSession(pendingRef, 300);

      if (resp.ok) {
        statusMessage.innerHTML = 'Verified! Redirecting...';
        continueBtn.style.display = 'inline-block';

        setTimeout(() => {
          window.location.href = LIBBY_URL;
        }, 1000);
      } else {
        throw new Error('Session verification failed');
      }
    } catch (error) {
      console.error('Polling error:', error);
      statusMessage.innerHTML = 'Verification timed out. <a href="javascript:location.reload()">Try again</a>';
    }
  }
</script>

 

Buy me a coffee