Vai al contenuto

Integrazione dei widget

Integra il widget ChatHub nel tuo sito web per fornire supporto chat in tempo reale ai tuoi clienti.

Panoramica

Il widget ChatHub è un componente JavaScript che:

  • Incorpora in qualsiasi sito web
  • Fornisce un'interfaccia di chat in tempo reale
  • Mette in contatto i clienti con gli operatori
  • Richiede il token di autenticazione dell'operatore
  • Carica come modulo ES

Avvio rapido

1. Ottieni il token operatore

Per prima cosa, ottieni un token operatore seguendo il flusso di autenticazione:

// 1. Get company token
const companyToken = await getCompanyToken(login, password);

// 2. Get organization
const organizations = await getOrganizations(companyToken);
const orgId = organizations[0].id;

// 3. Get operator
const operators = await getOperators(companyToken, orgId);
const operatorId = operators[0].id;

// 4. Generate operator token
const operatorToken = await getOperatorToken(
  companyToken,
  operatorId,
  expiresAt
);

// 5. Validate token
const isValid = await validateToken(companyToken, operatorToken);

2. Incorpora widget

Aggiungi lo script del widget al tuo HTML:

<!DOCTYPE html>
<html>
<head>
    <title>Your Website</title>
</head>
<body>
    <!-- Your website content -->

    <!-- ChatHub Widget -->
    <script type="module" id="operator-chat-panel-script"
      src="https://widget.smsbat.com/operator-chat-panel/widget-script.js"
      token="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."></script>
</body>
</html>

Parametri dello script

Attributo Valore Obbligatorio Descrizione
"tipo" modulo Tipo di modulo ES
id script-pannello-chat-operatore Identificatore univoco dello script
src URL del widget Posizione dello script del widget
gettone Gettone JWT Token di autenticazione dell'operatore

Metodi di integrazione

HTML statico

Per i siti Web statici, incorporali direttamente in HTML:

CODICE_BLOCCO_2

Iniezione dinamica (JavaScript)

Per le applicazioni a pagina singola, inserire dinamicamente:

function loadChatHubWidget(operatorToken) {
  // Check if widget already loaded
  const existing = document.getElementById('operator-chat-panel-script');
  if (existing) {
    existing.remove();
  }

  // Create script element
  const script = document.createElement('script');
  script.type = 'module';
  script.id = 'operator-chat-panel-script';
  script.src = 'https://widget.smsbat.com/operator-chat-panel/widget-script.js';
  script.setAttribute('token', operatorToken);

  // Append to body
  document.body.appendChild(script);
}

// Usage
const token = await getOperatorToken();
loadChatHubWidget(token);

Reagisci

import { useEffect } from 'react';

function ChatHubWidget({ operatorToken }) {
  useEffect(() => {
    if (!operatorToken) return;

    // Load widget
    const script = document.createElement('script');
    script.type = 'module';
    script.id = 'operator-chat-panel-script';
    script.src = 'https://widget.smsbat.com/operator-chat-panel/widget-script.js';
    script.setAttribute('token', operatorToken);

    document.body.appendChild(script);

    // Cleanup on unmount
    return () => {
      const existing = document.getElementById('operator-chat-panel-script');
      if (existing) {
        existing.remove();
      }
    };
  }, [operatorToken]);

  return null;
}

// Usage
function App() {
  const [token, setToken] = useState('');

  useEffect(() => {
    async function init() {
      const operatorToken = await fetchOperatorToken();
      setToken(operatorToken);
    }
    init();
  }, []);

  return (
    <div>
      <h1>My App</h1>
      <ChatHubWidget operatorToken={token} />
    </div>
  );
}

Vue.js

CODICE_BLOCCO_5

Angolare

CODICE_BLOCCO_6

Gestione dei token

Generazione di token lato server

Non esporre mai le credenziali aziendali nel codice lato client. Genera token sul tuo server:

CODICE_BLOCCO_7

Aggiornamento del token

Implementa l'aggiornamento automatico dei token:

class WidgetTokenManager {
  constructor() {
    this.token = null;
    this.expiresAt = null;
    this.refreshInterval = null;
  }

  async initialize() {
    await this.refreshToken();

    // Refresh token 1 hour before expiration
    this.refreshInterval = setInterval(
      () => this.checkAndRefresh(),
      60 * 60 * 1000 // Check every hour
    );
  }

  async refreshToken() {
    const response = await fetch('/api/chathub/token');
    const data = await response.json();

    this.token = data.token;
    this.expiresAt = new Date(data.expiresAt);

    this.reloadWidget();
  }

  async checkAndRefresh() {
    const oneHour = 60 * 60 * 1000;
    const timeUntilExpiry = this.expiresAt - Date.now();

    if (timeUntilExpiry < oneHour) {
      await this.refreshToken();
    }
  }

  reloadWidget() {
    // Remove old widget
    const existing = document.getElementById('operator-chat-panel-script');
    if (existing) {
      existing.remove();
    }

    // Load new widget with fresh token
    const script = document.createElement('script');
    script.type = 'module';
    script.id = 'operator-chat-panel-script';
    script.src = 'https://widget.smsbat.com/operator-chat-panel/widget-script.js';
    script.setAttribute('token', this.token);

    document.body.appendChild(script);
  }

  destroy() {
    if (this.refreshInterval) {
      clearInterval(this.refreshInterval);
    }
  }
}

// Usage
const widgetManager = new WidgetTokenManager();
await widgetManager.initialize();

Organizzazioni multiple

Carica widget diversi per organizzazioni diverse:

function loadWidgetForOrganization(organizationId) {
  return new Promise((resolve, reject) => {
    // Get operator for this organization
    fetch(`/api/chathub/token?org=${organizationId}`)
      .then(response => response.json())
      .then(data => {
        const script = document.createElement('script');
        script.type = 'module';
        script.id = `operator-chat-panel-script-${organizationId}`;
        script.src = 'https://widget.smsbat.com/operator-chat-panel/widget-script.js';
        script.setAttribute('token', data.token);

        script.onload = () => resolve();
        script.onerror = () => reject(new Error('Failed to load widget'));

        document.body.appendChild(script);
      })
      .catch(reject);
  });
}

// Usage
await loadWidgetForOrganization('sales');
await loadWidgetForOrganization('support');

Migliori pratiche

Sicurezza

  • ✅ Genera token lato server
  • ✅ Non esporre mai le credenziali aziendali nel codice cliente
  • ✅ Utilizza HTTPS per tutte le richieste API
  • ✅ Implementare la scadenza dei token
  • ✅ Convalida i token prima dell'uso
  • ❌ Non archiviare token in localStorage senza crittografia
  • ❌ Non impegnare i token nel controllo della versione

Prestazioni

  • ✅ Carica widget in modo asincrono
  • ✅ Utilizza i moduli ES (browser moderni)
  • ✅ Implementa la memorizzazione nella cache dei token
  • ✅ Gestisci gli errori con garbo
  • ❌Non bloccare il caricamento della pagina

Esperienza utente

  • ✅ Mostra lo stato di caricamento durante l'inizializzazione del widget
  • ✅ Gestire gli errori di rete
  • ✅ Fornire un metodo di contatto di riserva
  • ✅ Prova su diversi browser e dispositivi

Gestione degli errori

async function loadWidgetSafely(operatorToken) {
  try {
    // Validate token first
    const isValid = await validateToken(operatorToken);

    if (!isValid) {
      console.error('Invalid operator token');
      showFallbackContact();
      return;
    }

    // Load widget
    await loadWidget(operatorToken);

  } catch (error) {
    console.error('Failed to load chat widget:', error);
    showFallbackContact();
  }
}

function showFallbackContact() {
  // Show alternative contact method
  const fallback = document.createElement('div');
  fallback.innerHTML = `
    <div class="chat-fallback">
      <p>Chat is temporarily unavailable.</p>
      <p>Contact us: <a href="mailto:support@example.com">support@example.com</a></p>
    </div>
  `;
  document.body.appendChild(fallback);
}

Risoluzione dei problemi

Widget non caricato

  1. Verificare che il token dell'operatore sia valido
  2. Verifica che il token non sia scaduto
  3. Assicurarsi che l'URL dello script sia corretto
  4. Controlla la presenza di errori nella console del browser
  5. Verificare la connettività di rete

Gettone scaduto

// Detect expired token and refresh
window.addEventListener('error', async (event) => {
  if (event.message.includes('token expired')) {
    console.log('Token expired, refreshing...');
    await refreshWidgetToken();
  }
});

Istanze multiple di widget

Assicurati che venga caricato solo un widget alla volta:

CODICE_BLOCCO_12

Problemi multiorigine

Assicurati che il tuo dominio sia autorizzato. Contatta l'assistenza se riscontri errori CORS.

Test

Sviluppo locale

// Use test token for development
const isDevelopment = process.env.NODE_ENV === 'development';
const token = isDevelopment
  ? 'test-token-for-development'
  : await getProductionToken();

loadWidget(token);

Test di integrazione

CODICE_BLOCCO_14

Passaggi successivi