قائمة الأدلة

React Native

تضيف حزمة @kavchat/react-native إلى تطبيقكم دردشة دعم تعمل وفق سيناريو: موفّر سياق (Provider)، وشاشة دردشة، وزر عائم اختياري. تأتي الردود من السيناريوهات التي نشرتموها في لوحة التحكم، وتعمل على الجهاز.

التثبيت

الحزمة مكتوبة بالكامل بلغة JavaScript، دون أي كود أصلي خاص بها أو مكتبة أيقونات، لذا تعمل بالطريقة نفسها في تطبيق React Native عادي وفي Expo. الاعتماديات النظيرة: react من الإصدار 18 وreact-native من الإصدار 0.72.

React Native CLI (بدون Expo)

Terminal
yarn add @kavchat/react-native @react-native-async-storage/async-storage
cd ios && pod install

AsyncStorage وحدة أصلية: يربطها pod install على iOS، ويجري الربط تلقائيًا على Android.

Expo

تعمل في Expo Go وفي نسخ التطوير:

Terminal
yarn add @kavchat/react-native
npx expo install @react-native-async-storage/async-storage

بدون AsyncStorage

يحفظ AsyncStorage النسخة المنشورة والمحادثة بين مرات تشغيل التطبيق. تثبيته اختياري: بدونه، تحفظ الحزمة كل شيء في الذاكرة، فيعمل البوت، لكنه ينزّل النسخة من جديد عند كل تشغيل. لاستخدام وسيلة تخزين أخرى، مثل MMKV، مرّروا عبر الخاصية storage أي كائن { getItem, setItem, removeItem? }، متزامن أو غير متزامن:

TSX
import { MMKV } from 'react-native-mmkv';
const mmkv = new MMKV();
const storage = {
  getItem: (k: string) => mmkv.getString(k) ?? null,
  setItem: (k: string, v: string) => mmkv.set(k, v),
  removeItem: (k: string) => mmkv.delete(k),
};

<KavchatProvider publicKey="pk_live_..." storage={storage}>

الاستخدام

TSX
import { KavchatProvider, KavchatChat, KavchatLauncher, useKavchat } from '@kavchat/react-native';

export default function App() {
  return (
    <KavchatProvider publicKey="pk_live_..." onScreen={(screen, id) => navigation.navigate(screen, { id })}>
      <Navigation />
      {/* floating button, bottom end corner; opens the chat in a modal */}
      <KavchatLauncher />
    </KavchatProvider>
  );
}

// or as a screen in your own navigator
function SupportScreen() {
  return <KavchatChat />;
}

// or your own button
function HelpButton() {
  const { available, open } = useKavchat();
  if (!available) return null; // bot is off, limited to testers, or over quota
  return <Button title="Help" onPress={open} />;
}

خصائص KavchatProvider

الخاصيةالوصف
publicKeypk_live_... من لوحة التحكم. يمكن تضمينه في التطبيق.
apiBaseالقيمة الافتراضية: https://api.kavchat.com.
localeلغة الواجهة (he، en، ar، ru، es، fr، de، pt، it، tr). الافتراضي: لغة الجهاز، وإذا لم تتوفر ترجمة لها، تُستخدم لغة البوت. تجري المطابقة مع السيناريوهات دائمًا بلغة البوت.
userToken, userNameتحديد هوية المستخدم، انظروا أدناه.
onScreen(screen, targetId?)تُستدعى عند الضغط على زر من نوع "شاشة" في السيناريو. بدونها، لا تفعل هذه الأزرار شيئًا.
screensالشاشات التي يستطيع التطبيق فتحها، لعرضها في القائمة المنسدلة في المحرّر. راجعوا قائمة الشاشات في المحرّر.
onEvent(event)ready، unavailable، effect، ticket.
storageأي كائن { getItem, setItem, removeItem? }، متزامن أو غير متزامن. الافتراضي: AsyncStorage، وإذا لم يكن مثبتًا، تُستخدم الذاكرة.
themeتغيير الألوان، راجعوا الألوان واتجاه RTL.

تُرجع useKavchat() الكائن { status, available, offline, locale, isOpen, open, close, toggle, setUser, startNewConversation, openContactForm, controller }.

خصائص KavchatChat: onClose? (تُظهر زر إغلاق)، وhideHeader? وstyle?. خصائص KavchatLauncher: style? (الموضع)، وonPress? (لفتح شاشة خاصة بكم بدلًا من النافذة المدمجة)، وattention? (القيمة false تعطّل الرسالة).

عند إعداد رسالة بجانب زر الدردشة في شاشة الإدارة (فقاعة كلام أو نص مقوّس فوق الزر)، يعرضها KavchatLauncher بعد المهلة المحددة، مرة واحدة يوميًا كحد أقصى. يؤدي إغلاق الرسالة أو فتح الدردشة إلى إخفائها حتى اليوم التالي. لا تظهر الرسالة عندما تكون الدردشة مفتوحة. وعند تفعيل تقليل الحركة على الجهاز، تظهر الرسالة دون حركة. عند تفعيل خيار "عدم العرض على الهواتف"، تظهر الرسالة على الأجهزة اللوحية فقط (عندما يكون طول الضلع الأقصر للشاشة 600 نقطة أو أكثر).

رمز الهوية

بدون رمز، يُعدّ المستخدم ضيفًا، ويطلب منه نموذج التواصل بريدًا إلكترونيًا أو رقم هاتف. لتحديد هوية مستخدم مسجّل الدخول، وقّعوا JWT قصير الصلاحية على خادمكم باستخدام المفتاح السري (وليس داخل التطبيق أبدًا، راجعوا تحديد هوية المستخدمين)، ومرّروه بهذه الطريقة:

TSX
<KavchatProvider publicKey="pk_live_..." userToken={session?.kavchatToken} userName={session?.firstName}>

يؤدي تغيير userToken (تسجيل الدخول أو الخروج) إلى إعادة تحميل النسخة، لأن مجموعة مستخدمي الاختبار تعتمد على هوية المستخدم. يمكنكم أيضًا استدعاء useKavchat().setUser({ token, name }). يُرسل الرمز في ترويسة Authorization: Bearer فقط، ولا يُحفظ على الجهاز. ترتبط المحادثة المحفوظة ببصمة الرمز، لذا يبدأ أي مستخدم آخر على الجهاز نفسه محادثة جديدة.

الروابط والشاشات ونموذج التواصل

  • الأزرار من نوع link تفتح عناوين https: وtel: فقط، عبر Linking.openURL. لا تُفتح أنواع العناوين الأخرى.
  • الأزرار من نوع screen تستدعي onScreen. تبقى الدردشة في موضعها.
  • يفتح زر "التواصل مع الفريق" نموذج التواصل مع إرفاق المحادثة. بعد الإرسال، يظهر رقم التذكرة.

قائمة الشاشات في المحرّر

عرّفوا الشاشات التي يستطيع التطبيق فتحها مرة واحدة في خاصية screens ضمن KavchatProvider. ترسل حزمة SDK القائمة إلى Kavchat تلقائيًا، ويعرض محرّر السيناريوهات هذه الشاشات بأسمائها في قائمة منسدلة بدلًا من حقل نص حر. يطلب المحرّر أيضًا معرّف عنصر عندما تحتاجه الشاشة، وينبّه إلى أي زر يؤدي إلى شاشة لم تُعرَّف. لا حاجة إلى إدخال قائمة الشاشات يدويًا في لوحة التحكم.

TSX
const screens = [
  { id: 'orders', label: 'My orders' },
  { id: 'product', label: 'Product page', needsTarget: true }, // the button also carries a product id
];

<KavchatProvider
  publicKey="pk_live_..."
  screens={screens}
  onScreen={(screen, targetId) => navigation.navigate(screen, targetId ? { id: targetId } : undefined)}
>
  • id هو القيمة التي تصل إلى onScreen: أحرف لاتينية وأرقام و_ و. و-، بحد أقصى 40 محرفًا. label هو الاسم الذي يراه المسؤول، بحد أقصى 60 محرفًا. الحد الأقصى 100 شاشة. تُستبعد السجلات غير الصالحة والمعرّفات المكررة.
  • needsTarget: يحمل الزر أيضًا معرّف عنصر (مثل معرّف منتج)، ويصل إلى onScreen باسم targetId.
  • تُرسل القائمة في الخلفية بعد تحميل النسخة، فقط عند تغيّرها أو مرة في الأسبوع. إذا فشل الإرسال، يحدث ذلك دون تنبيه، وتُعاد المحاولة عند التشغيل التالي. لا يرى المستخدم شيئًا.
  • تظهر الشاشات المسجّلة في لوحة التحكم ضمن البوت، ثم الإعدادات، ثم "شاشات التطبيق"، مع المنصات التي أبلغت عن كل شاشة. يمكنكم حذف أي شاشة أزلتموها من التطبيق من هناك.

الألوان واتجاه RTL

تأتي الألوان من إعدادات البوت في لوحة التحكم (primaryColor)، ويُختار لون النص فوقه وفق تباين WCAG. يمكنكم تغيير أي منها: primary وbackground وbotBubble وuserBubble وtext وmuted وaccent وonPrimary وerror:

TSX
<KavchatProvider
  publicKey="pk_live_..."
  theme={{ primary: '#0f766e', background: '#ffffff' }}
>

الحزمة لا تغيّر اتجاه تخطيط التطبيق. بل تتبع I18nManager.isRTL (أنماط start وend)، وتُحاذي كل نص حسب لغته، فتُقرأ العبرية والعربية بشكل صحيح حتى في تطبيق يتجه من اليسار إلى اليمين. إذا كان تطبيقكم بالعبرية أو العربية، اضبطوا اتجاه RTL فيه مرة واحدة كالمعتاد: I18nManager.forceRTL(true) ثم أعيدوا تشغيله.

تظهر شارة "مدعوم من Kavchat by maxsave" في جميع الخطط، مع رابط إلى kavchat.com. في بريميوم، يمكنكم إخفاؤها من إعدادات البوت.

الدردشة مع موظف دعم

لا تحتاجون إلى إعدادات للبدء. عند تفعيل الدردشة مع موظفي الدعم في شاشة الإدارة، يظهر الخيار في دردشة التطبيق تمامًا كما في أداة الدردشة للموقع.

  • الخيار: يظهر "التحدث مع موظف دعم" قبل "التواصل مع الفريق"، وفقط بعد تأكيد الخادم وجود موظف متاح. يُتحقق من التوفر مجددًا عند الضغط على الزر. خارج ساعات العمل، أو عندما يكون جميع الموظفين مشغولين، يظهر نموذج التواصل فقط، مع شرح قصير وموعد عودة الفريق إذا كان معروفًا. عند نفاد الحصة الشهرية، يظهر النموذج دون شرح.
  • الطلب: يترك الضيوف بريدًا إلكترونيًا أو رقم هاتف، في حال لم يتفرغ أي موظف في الوقت المحدد. ويمكنهم أيضًا إضافة اسم ورسالة أولى. عندما يكون أكثر من قسم واحد متاحًا، يختارون قسمًا. لا يحتاج المستخدمون الذين جرى تحديد هويتهم (userToken) إلى إدخال بيانات التواصل. إذا لم يتمكن أي موظف من استقبال المحادثة، يُفتح نموذج التواصل بالبيانات المُدخلة مسبقًا.
  • الانتظار: تظهر عبارة "بانتظار موظف دعم" مع عدّ تنازلي حتى انتهاء مدة الانتظار التي حددتموها، وبجانبها الزران "ترك رسالة بدلًا من ذلك" و"إنهاء المحادثة". يمكن الكتابة أثناء الانتظار. عند انتهاء المدة، تتحول المحادثة تلقائيًا إلى تذكرة. يظهر رقم التذكرة مع توضيح أن أي موظف لم يتفرغ في الوقت المحدد.
  • المحادثة: اسم الموظف، والرسائل، ومؤشر الكتابة، والتحويل إلى موظف آخر، وإنهاء المحادثة. يُعرض كل ما يصل من الخادم كنص عادي، دون روابط.
  • في الوقت الفعلي: اتصال Server-Sent Events عبر XMLHttpRequest (أو البث عبر fetch حيث يتوفر). إذا انقطع الاتصال، تعيد الدردشة الاتصال بفواصل زمنية متزايدة، وتسترجع كل ما فاتها. وهكذا لا تضيع أي رسالة ولا تظهر مرتين. في الشبكات التي تحجب هذا الاتصال، تنتقل الدردشة إلى الاستعلام المتكرر (long-poll). لكل رسالة معرّف، لذا لا تؤدي إعادة المحاولة إلى تكرارها. تُميَّز الرسالة التي لم تُرسل، ويمكن إعادة إرسالها بنقرة.
  • الانتقال إلى الخلفية وإعادة التشغيل: عندما ينتقل التطبيق إلى الخلفية، يُغلق الاتصال. وعند عودته، تسترجع الدردشة ما فاتها. يظل رمز الوصول إلى المحادثة صالحًا لمدة تصل إلى 12 ساعة أو حتى انتهاء المحادثة، ويُحفظ في وسيلة التخزين التي تختارونها. وهكذا تعود المحادثة المفتوحة إلى الشاشة بعد إعادة تشغيل التطبيق. لا يُحفظ الرمز في العنوان ولا يُكتب في السجل.
  • لا توجد إشعارات دفع في هذه النسخة: تصل رسائل الموظف فقط عندما يكون التطبيق مفتوحًا.

يُنصح بحفظ رمز الوصول في تخزين آمن (Keychain على iOS، وKeystore على Android). إذا لم تضبطوا secureStorage، يُحفظ الرمز في وسيلة تخزين المحادثة نفسها. يفتح الزر الخاص بكم للتحدث مع موظف دعم نموذج الطلب عند توفر موظف. وإذا لم يتوفر موظف، يُفتح نموذج التواصل مع الشرح:

TSX
import * as SecureStore from 'expo-secure-store';

// expo-secure-store allows only [A-Za-z0-9._-] in keys
const safe = (k: string) => k.replace(/[^A-Za-z0-9._-]/g, '_');
const secureStorage = {
  getItem: (k: string) => SecureStore.getItemAsync(safe(k)),
  setItem: (k: string, v: string) => SecureStore.setItemAsync(safe(k), v),
  removeItem: (k: string) => SecureStore.deleteItemAsync(safe(k)),
};

<KavchatProvider publicKey="pk_live_..." secureStorage={secureStorage} livePage="checkout">

// your own button
const { openLive } = useKavchat();
<Button title="Chat with us" onPress={openLive} />

الأحداث: تتلقى onEvent الكائن { type: 'live', phase } عند كل تغيير في حالة المحادثة (queued، active، closed، ticket، replaced، expired).

الأسئلة والشروط والعملاء المحتملون

لا حاجة إلى إعدادات في التطبيق. يمكن للسيناريو طلب بيانات (اسم، أو رقم هاتف، أو بريد إلكتروني، أو رقم، أو نص)، وتحديد كيفية المتابعة وفق شروط (بريميوم)، وإرسال بيانات عميل محتمل. كل شيء يعمل على الجهاز.

  • لوحة مفاتيح مناسبة: عندما ينتظر البوت إجابة، يعرض حقل النص لوحة مفاتيح للهاتف أو البريد الإلكتروني أو الأرقام، مع الإكمال التلقائي. إذا كانت الإجابة غير صالحة، يوضح البوت ما ينقصها ويُميَّز الحقل. يظهر زر "تخطي" للأسئلة التي يمكن تخطيها.
  • العميل المحتمل: عند وجود نص للموافقة، يظهر الزران "إرسال" و"لا، شكرًا". إذا لم يتوفر اتصال بالشبكة، تُحفظ بيانات العميل المحتمل على الجهاز وتُرسل عند عودة الاتصال، دون تكرار.
  • التعبئة المسبقة: تُستخدم الإجابات التي قدّمها المستخدم لملء نموذج التواصل ونموذج طلب التحدث مع موظف دعم، وتُرفق بالتذكرة والمحادثة مع الموظف. يُعدّ الاسم والبريد الإلكتروني ورقم الهاتف من رمز الهوية إجابات معروفة، فلا يسأل عنها البوت مجددًا.
  • الشاشة الحالية: تحدد livePage أيضًا الشاشة التي تتحقق منها الشروط والتي تُرسل مع بيانات العملاء المحتملين. يؤدي تغيير الخاصية إلى تحديثها.

إجابات الذكاء الاصطناعي (بريميوم)

لا حاجة إلى إعداد أي شيء في التطبيق. عند تفعيل إجابات الذكاء الاصطناعي في شاشة الإدارة (باستخدام مفتاحكم الخاص لدى مزوّد ذكاء اصطناعي)، يُرسل السؤال الذي لا يجيب عنه أي سيناريو إلى Kavchat. وأثناء الانتظار، لمدة تصل إلى 20 ثانية، تُظهر الدردشة أن البوت يكتب. تظهر الإجابة كنص عادي مع وسم صغير "إجابة الذكاء الاصطناعي" بلغة الواجهة، وأسفلها زر لموضوع ذي صلة إن وُجد، وزر "التواصل مع الفريق".

إذا لم تتوفر إجابة، أو فشل الطلب، أو استغرق وقتًا أطول من المسموح، أو تجاوز الحد (10 إجابات لكل محادثة كل 15 دقيقة)، تعرض الدردشة الرسالة المعتادة "لم أجد إجابة". يظل السؤال ظاهرًا في تقرير الأسئلة التي لم تُوجد لها إجابة، وتُحفظ إجابات الذكاء الاصطناعي في المحادثة المحفوظة مثل أي رسالة أخرى.

آلية العمل

  • تُحفظ النسخة المنشورة في ذاكرة التخزين المؤقت مع ETag الخاص بها (If-None-Match، 304). عند غياب الشبكة، تُعرض النسخة المحفوظة مع رسالة توضح ذلك.
  • تُحفظ المحادثة على الجهاز ويمكن استعادتها خلال 24 ساعة، ما دامت النسخة والمستخدم لم يتغيرا.
  • يُرسل تقرير عن مسار المحادثة بعد 2 ثانية من آخر إجراء، وكذلك عندما ينتقل التطبيق إلى الخلفية.
  • لا تُرسل الطلبات ترويسات مخصصة، بل Authorization وContent-Type وIf-None-Match فقط.