Меню руководств

React Native

Пакет @kavchat/react-native добавляет в приложение чат поддержки по сценарию: провайдер, экран чата и, по желанию, плавающую кнопку. Ответы берутся из сценариев, опубликованных в панели управления, и обрабатываются на устройстве.

Установка

Пакет полностью написан на JavaScript, без собственного нативного кода и библиотеки иконок, поэтому одинаково работает в обычном приложении React Native и в Expo. Peer-зависимости: 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 точек или больше).

Токен идентификации

Без токена пользователь считается гостем, и форма обращения запрашивает у него email или телефон. Чтобы идентифицировать вошедшего в аккаунт пользователя, подпишите короткоживущий 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 отображается на всех тарифах. На тарифе Премиум её можно скрыть в настройках бота.

Чат с оператором

Для начала не нужны дополнительные настройки. Когда вы включаете чат с операторами в панели управления, эта возможность появляется в чате приложения так же, как в виджете для сайта.

  • Доступность: кнопка «Чат с оператором» появляется перед кнопкой «Написать команде», только после подтверждения сервером, что есть свободный оператор. При нажатии доступность проверяется повторно. В нерабочее время или когда все операторы заняты отображается только форма обращения с кратким пояснением и временем возвращения команды, если оно известно. Когда месячная квота исчерпана, форма показывается без пояснения.
  • Запрос на чат: гости оставляют email или телефон на случай, если ни один оператор не освободится вовремя. Можно также добавить имя и первое сообщение. Если открыто несколько отделов, нужно выбрать отдел. Идентифицированным пользователям (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).

Вопросы, условия и лиды

Настройки в приложении не нужны. Сценарий может запрашивать данные (имя, телефон, email, число или текст), выбирать дальнейшие действия по условиям (Премиум) и отправлять лид. Всё выполняется на устройстве.

  • Подходящая клавиатура: когда бот ждёт ответа, поле ввода открывает клавиатуру для телефона, email или чисел с автозаполнением. Если ответ некорректен, бот объясняет, чего не хватает, а поле выделяется. У вопроса, который можно пропустить, появляется кнопка «Пропустить».
  • Лид: если есть текст согласия, появляются кнопки «Отправить» и «Нет, спасибо». Без подключения к сети лид сохраняется на устройстве и отправляется при восстановлении связи, без дубликатов.
  • Предзаполнение: ответы, которые пользователь уже дал, подставляются в форму обращения и форму запроса на чат с оператором, а также прикладываются к обращению и чату с оператором. Имя, email и телефон из токена идентификации считаются известными ответами, и бот не запрашивает их повторно.
  • Текущий экран: livePage также указывает экран, который проверяется в условиях и передаётся вместе с лидами. Изменение свойства обновляет это значение.

Ответы ИИ (Премиум)

В приложении ничего настраивать не нужно. Если в панели управления включены ответы ИИ (с вашим собственным ключом провайдера ИИ), вопрос, на который не отвечает ни один сценарий, отправляется в Kavchat. Во время ожидания, до 20 секунд, чат показывает, что бот набирает текст. Ответ отображается как обычный текст с небольшой меткой «Ответ ИИ» на языке интерфейса. Под ним появляются кнопка связанной темы, если она есть, и кнопка «Написать команде».

Если ответа нет, запрос завершился ошибкой, занял слишком много времени или превысил лимит (10 ответов на диалог за каждые 15 минут), чат показывает обычное сообщение «Не удалось найти ответ». Вопрос по-прежнему попадает в отчёт о вопросах без ответа, а ответы ИИ сохраняются в переписке, как и любые другие сообщения.

Как это работает

  • Опубликованная версия кешируется вместе с её ETag (If-None-Match, 304). Без сети отображается сохранённая версия с соответствующим сообщением.
  • Переписка сохраняется на устройстве и восстанавливается в течение 24 часов, если версия и пользователь не изменились.
  • Данные о ходе диалога отправляются через 2 секунды после последнего действия, а также при переходе приложения в фоновый режим.
  • Запросы не отправляют пользовательские заголовки, только Authorization, Content-Type и If-None-Match.