အကြောင်းအရာသို့ ကရန်

Widget ပေါင်းစည်းခြင်း။

သင့်ဖောက်သည်များအတွက် အချိန်နှင့်တစ်ပြေးညီ ချတ်ပံ့ပိုးမှုပေးရန်အတွက် ChatHub ဝစ်ဂျက်ကို သင့်ဝဘ်ဆိုဒ်တွင် ပေါင်းစပ်ပါ။

ခြုံငုံသုံးသပ်ချက်

ChatHub widget သည် JavaScript အစိတ်အပိုင်းတစ်ခုဖြစ်သည်-

  • မည်သည့် website တွင်မဆိုထည့်သွင်းပါ။
  • အချိန်နှင့်တစ်ပြေးညီ chat interface ကိုပေးသည်။
  • အော်ပရေတာများနှင့်ဖောက်သည်များကိုချိတ်ဆက်ပါ။
  • အော်ပရေတာ စစ်မှန်ကြောင်းအထောက်အထားပြခြင်း တိုကင်လိုအပ်သည်။
  • ES မော်ဂျူးအဖြစ် တင်ပေးသည်။

အမြန်စတင်ပါ။

1. အော်ပရေတာတိုကင်ရယူပါ။

ပထမဦးစွာ၊ authentication flow တွင် အောက်ပါ အော်ပရေတာ တိုကင်တစ်ခုကို ရယူပါ။

// 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 တွင် widget script ကိုထည့်ပါ။

<!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>

Script ကန့်သတ်ချက်များ

ဂုဏ်ရည် တန်ဖိုး လိုအပ်သည် ဖော်ပြချက်
ရိုက် module ဟုတ်တယ် ES module အမျိုးအစား
id operator-chat-panel-script ဟုတ်တယ် သီးသန့် script identifier
src ဝစ်ဂျက် URL ဟုတ်တယ် ဝစ်ဂျက် ဇာတ်ညွှန်းတည်နေရာ
တိုကင် JWT တိုကင် ဟုတ်တယ် အော်ပရေတာ စစ်မှန်ကြောင်းအထောက်အထားပြ တိုကင်

ပေါင်းစည်းရေးနည်းလမ်းများ

Static 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>

Dynamic Injection (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);
  }
}

တိုကင်စီမံခန့်ခွဲမှု

Server-Side Token မျိုးဆက်

ကုမ္ပဏီ၏အထောက်အထားများကို client-side ကုဒ်တွင် ဘယ်သောအခါမှ မဖော်ပြပါ။ သင့်ဆာဗာတွင် တိုကင်များကို ထုတ်ပါ-

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

အကောင်းဆုံးအလေ့အကျင့်များ

လုံခြုံရေး

  • ✅ တိုကင်များကို ဆာဗာ-ဘက်တွင် ထုတ်လုပ်ပါ။
  • ✅ ဖောက်သည်ကုဒ်တွင် ကုမ္ပဏီအထောက်အထားများကို ဘယ်သောအခါမှ မဖော်ပြပါနှင့်
  • ✅ API တောင်းဆိုမှုအားလုံးအတွက် HTTPS ကိုသုံးပါ။
  • ✅ တိုကင်သက်တမ်းကုန်ဆုံးမှုကို အကောင်အထည်ဖော်ပါ။
  • ✅ အသုံးမပြုမီ တိုကင်များကို စစ်ဆေးပါ။
  • ❌ ကုဒ်ဝှက်ခြင်းမရှိဘဲ localStorage တွင် တိုကင်များကို မသိမ်းဆည်းပါနှင့်
  • ❌ ဗားရှင်းထိန်းချုပ်မှုတွင် တိုကင်များကို မကျူးလွန်ပါနှင့်

စွမ်းဆောင်ရည်

  • ✅ ဝစ်ဂျက်ကို တပြိုင်တည်းတင်ပါ။
  • ✅ ES modules (ခေတ်မီဘရောက်ဆာများ) ကိုသုံးပါ။
  • ✅ တိုကင် သိမ်းဆည်းခြင်းကို အကောင်အထည်ဖော်ပါ။ ✅ အမှားများကို သပ်ရပ်စွာ ကိုင်တွယ်ပါ။
  • ❌ page load ကို မပိတ်ပင်ပါနှင့်

အသုံးပြုသူအတွေ့အကြုံ

  • ✅ ဝစ်ဂျက်စတင်စဉ်တွင် loading state ကိုပြသပါ။
  • ✅ ကွန်ရက်အမှားအယွင်းများကို ကိုင်တွယ်ပါ။
  • ✅ ပြန်လည်ဆက်သွယ်ရန်နည်းလမ်းကိုပေးပါ။
  • ✅ မတူညီသောဘရောက်ဆာများနှင့် စက်များတွင် စမ်းသပ်ပါ။

မှားယွင်းကိုင်တွယ်ခြင်း။

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. script 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');
    }
  });
});

နောက်အဆင့်များ

  • Authentication - တိုကင်များကို စီမံပါ။
  • အော်ပရေတာ - အော်ပရေတာများကို စနစ်ထည့်သွင်းပါ။
  • Organizations - အဖွဲ့အစည်းများကို စီစဉ်သတ်မှတ်ပါ။