תפריט המדריכים

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. ערכת הפיתוח שולחת את הרשימה ל-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 שעות או עד שהשיחה מסתיימת, ונשמר באחסון שתבחרו. כך, אחרי הפעלה מחדש של האפליקציה, שיחה פתוחה חוזרת למסך. האישור לא נשמר בכתובת ולא נכתב ללוג.
  • אין התראות push בגרסה הזו: הודעות מהנציג מגיעות רק כשהאפליקציה פתוחה.

מומלץ לשמור את אישור הגישה באחסון מאובטח (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 מציין גם את המסך שהתנאים בודקים ושנשלח עם לידים. שינוי ה-prop מעדכן אותו.

תשובות AI (פרימיום)

אין מה להגדיר באפליקציה. כשמפעילים תשובות AI במסך הניהול (עם מפתח של ספק AI משלכם), שאלה שאף תסריט לא עונה עליה נשלחת ל-Kavchat, ובזמן ההמתנה, עד 20 שניות, הצ'אט מראה שהבוט מקליד. התשובה מוצגת כטקסט רגיל עם תווית קטנה "תשובת AI" בשפת הממשק, ומתחתיה כפתור לנושא קשור, אם יש כזה, וכפתור "פנייה לצוות".

אם אין תשובה, או שהבקשה נכשלה, לקחה יותר מדי זמן או עברה את המגבלה (10 תשובות לשיחה בכל 15 דקות), הצ'אט מציג את ההודעה הרגילה של "לא מצאתי תשובה". השאלה עדיין מופיעה בדוח השאלות שלא נמצאה להן תשובה, ותשובות AI נשמרות בשיחה השמורה כמו כל הודעה אחרת.

התנהגות

  • הגרסה שפורסמה נשמרת במטמון עם ה-ETag שלה (If-None-Match, 304). כשאין רשת מוצגת הגרסה השמורה, עם הודעה על כך.
  • השיחה נשמרת במכשיר ומשוחזרת במשך 24 שעות, כל עוד הגרסה והמשתמש לא השתנו.
  • מהלך השיחה מדווח 2 שניות אחרי הפעולה האחרונה, וגם כשהאפליקציה עוברת לרקע.
  • הבקשות לא שולחות כותרות מותאמות, רק Authorization, Content-Type ו-If-None-Match.