შიგთავსზე გადასვლა

ვიჯეტის ინტეგრაცია

ჩადეთ ChatHub ვიჯეტი თქვენს ვებსაიტში, რათა უზრუნველყოთ რეალურ დროში ჩატის მხარდაჭერა თქვენი მომხმარებლებისთვის.

მიმოხილვა

ChatHub ვიჯეტი არის JavaScript კომპონენტი, რომელიც:

  • ჩაშენებულია ნებისმიერ ვებსაიტში
  • გთავაზობთ რეალურ დროში ჩატის ინტერფეისს
  • აკავშირებს მომხმარებელს ოპერატორებთან
  • მოითხოვს ოპერატორის ავთენტიფიკაციის ჟეტონს
  • იტვირთება როგორც ES მოდული

სწრაფი დაწყება

1. მიიღეთ ოპერატორის ნიშანი

პირველ რიგში, მიიღეთ ოპერატორის ჟეტონი ავთენტიფიკაციის ნაკადის შემდეგ:

// 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. ვიჯეტის ჩაშენება

დაამატეთ ვიჯეტის სკრიპტი თქვენს 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>

სკრიპტის პარამეტრები

ატრიბუტი ღირებულება საჭირო აღწერა
ტიპი მოდული დიახ ES მოდულის ტიპი
id operator-chat-panel-script დიახ სკრიპტის უნიკალური იდენტიფიკატორი
src ვიჯეტის URL დიახ ვიჯეტის სკრიპტის მდებარეობა
ჟეტონი JWT ჟეტონი დიახ ოპერატორის ავთენტიფიკაციის ჟეტონი

ინტეგრაციის მეთოდები

სტატიკური HTML

სტატიკური ვებსაიტებისთვის, ჩადეთ პირდაპირ HTML-ში:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Website</title>
</head>
<body>
    <h1>Welcome to My Website</h1>

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

დინამიური ინექცია (JavaScript)

ერთგვერდიანი აპლიკაციებისთვის, ინექცია დინამიურად:

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);

რეაგირება

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

<template>
  <div id="app">
    <h1>My App</h1>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      operatorToken: ''
    };
  },
  async mounted() {
    // Get operator token
    this.operatorToken = await this.fetchOperatorToken();

    // Load widget
    this.loadWidget();
  },
  methods: {
    async fetchOperatorToken() {
      // Your token fetching logic
      const response = await fetch('/api/chathub/token');
      return response.text();
    },
    loadWidget() {
      if (!this.operatorToken) return;

      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.operatorToken);

      document.body.appendChild(script);
    }
  },
  beforeUnmount() {
    const script = document.getElementById('operator-chat-panel-script');
    if (script) {
      script.remove();
    }
  }
};
</script>

კუთხოვანი

import { Component, OnInit, OnDestroy } from '@angular/core';

@Component({
  selector: 'app-root',
  template: '<h1>My App</h1>'
})
export class AppComponent implements OnInit, OnDestroy {
  private operatorToken: string = '';

  async ngOnInit() {
    // Get operator token
    this.operatorToken = await this.fetchOperatorToken();

    // Load widget
    this.loadWidget();
  }

  ngOnDestroy() {
    const script = document.getElementById('operator-chat-panel-script');
    if (script) {
      script.remove();
    }
  }

  private async fetchOperatorToken(): Promise<string> {
    const response = await fetch('/api/chathub/token');
    return response.text();
  }

  private loadWidget() {
    if (!this.operatorToken) return;

    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.operatorToken);

    document.body.appendChild(script);
  }
}

ჟეტონ მენეჯმენტი

სერვერის ტოკენის გენერაცია

** არასოდეს გაამჟღავნოთ კომპანიის რწმუნებათა სიგელები კლიენტის მხარეს კოდით.** შექმენით ტოკენები თქვენს სერვერზე:

// Node.js Express example
const express = require('express');
const app = express();

app.get('/api/chathub/token', async (req, res) => {
  try {
    // Authenticate your user first
    const userId = req.session.userId;
    if (!userId) {
      return res.status(401).json({ error: 'Unauthorized' });
    }

    // Get company token (stored securely on server)
    const companyToken = process.env.CHATHUB_COMPANY_TOKEN;

    // Get operator ID for this user
    const operatorId = await getOperatorIdForUser(userId);

    // Generate operator token
    const operatorToken = await generateOperatorToken(
      companyToken,
      operatorId
    );

    res.json({ token: operatorToken });
  } catch (error) {
    res.status(500).json({ error: 'Failed to generate token' });
  }
});

async function generateOperatorToken(companyToken, operatorId) {
  const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours

  const response = await fetch(
    'https://chatapi.smsbat.com/api/operator/get-token',
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${companyToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        id: operatorId,
        expiresAt: expiresAt.toISOString()
      })
    }
  );

  return response.text();
}

ტოკენის განახლება

განახორციელეთ ტოკენის ავტომატური განახლება:

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();

მრავალი ორგანიზაცია

ჩატვირთეთ სხვადასხვა ვიჯეტები სხვადასხვა ორგანიზაციისთვის:

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');

საუკეთესო პრაქტიკა

უსაფრთხოება

  • ✅ ტოკენების გენერირება სერვერის მხრიდან
  • ✅ არასოდეს გაამჟღავნოთ კომპანიის რწმუნებათა სიგელები კლიენტის კოდში
  • ✅ გამოიყენეთ HTTPS ყველა API მოთხოვნისთვის
  • ✅ განახორციელეთ ტოკენის ვადის გასვლა
  • ✅ დაადასტურეთ ტოკენები გამოყენებამდე
  • ❌ არ შეინახოთ ტოკენები localStorage-ში დაშიფვრის გარეშე
  • ❌ არ დადოთ ნიშნები ვერსიის კონტროლზე

შესრულება

  • ✅ ვიჯეტის ასინქრონულად ჩატვირთვა
  • ✅ გამოიყენეთ ES მოდულები (თანამედროვე ბრაუზერები)
  • ✅ განახორციელეთ ტოკენის ქეშირება
  • ✅ შეცდომებს მოხდენილად გაუმკლავდეთ
  • ❌ არ დაბლოკოთ გვერდის ჩატვირთვა

მომხმარებლის გამოცდილება

  • ✅ ჩატვირთვის მდგომარეობის ჩვენება ვიჯეტის ინიციალიზაციისას
  • ✅ გაუმკლავდეს ქსელის შეცდომებს
  • ✅ უზრუნველყოს სარეზერვო კონტაქტის მეთოდი
  • ✅ ტესტირება სხვადასხვა ბრაუზერებსა და მოწყობილობებზე

შეცდომის დამუშავება

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);
}

პრობლემების მოგვარება

ვიჯეტი არ იტვირთება

  1. შეამოწმეთ ოპერატორის ჟეტონი მოქმედებს
  2. დარწმუნდით, რომ ჟეტონს ვადა არ გაუვიდა
  3. დარწმუნდით, რომ სკრიპტის URL სწორია
  4. შეამოწმეთ ბრაუზერის კონსოლი შეცდომებისთვის
  5. შეამოწმეთ ქსელის კავშირი

ჟეტონს ვადა გაუვიდა

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

ვიჯეტის მრავალი შემთხვევა

დარწმუნდით, რომ მხოლოდ ერთი ვიჯეტი იტვირთება ერთდროულად:

function loadWidgetOnce(token) {
  // Remove any existing widgets
  const existingScripts = document.querySelectorAll(
    'script[id^="operator-chat-panel-script"]'
  );

  existingScripts.forEach(script => script.remove());

  // Load new widget
  loadWidget(token);
}

ჯვარედინი წარმოშობის საკითხები

დარწმუნდით, რომ თქვენი დომენი თეთრ სიაშია. დაუკავშირდით მხარდაჭერას, თუ შეხვდებით CORS შეცდომებს.

ტესტირება

ლოკალური განვითარება

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

loadWidget(token);

ინტეგრაციის ტესტირება

describe('ChatHub Widget', () => {
  it('should load widget with valid token', async () => {
    const token = await getTestToken();
    loadWidget(token);

    await waitFor(() => {
      const widget = document.getElementById('operator-chat-panel-script');
      expect(widget).toBeTruthy();
    });
  });

  it('should handle invalid token', async () => {
    const invalidToken = 'invalid-token';

    try {
      await loadWidget(invalidToken);
    } catch (error) {
      expect(error.message).toContain('Invalid token');
    }
  });
});

შემდეგი ნაბიჯები