Диалог с оператором
Privacy, реакции, inline-клавиатуры, system cards, кнопка «Закрыть тикет», лайтбокс для фото.
Как устроен диалог
Диалог — это самая «живая» часть виджета. Сверху hero-блок с приветствием («Добро пожаловать!» + время ответа), под ним — скроллируемая лента сообщений, внизу — композер.
Что выводится в ленте:
- Bubble посетителя — справа, акцентного цвета.
- Bubble оператора — слева, с аватаркой (своя или fallback на лого workspace) и именем.
- System card — серая центрированная плашка для событий тикета: оператор назначен, тикет передан в отдел, отложен/возобновлён, закрыт.
- Inline keyboard — кнопки под bubble оператора, если он их прикрепил (URL, deeplink, callback).
Privacy
SettingsWidget BuilderConversationPrivacy — три флага, которые управляют видимостью индикаторов.
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
| conversation.privacy.typing_enabled | boolean | true | Показывать визитёру индикатор «оператор печатает». Когда выключено — оператор печатает «в тишине», визитёр узнаёт о сообщении только когда оно отправилось. |
| conversation.privacy.read_receipts_enabled | boolean | true | Галочки ✓✓ под исходящими сообщениями посетителя. Если выключено, посетитель не видит, прочитан ли его пост. |
| conversation.privacy.operator_seen_enabled | boolean | true | Подпись «✓✓ прочитано» под последним сообщением посетителя после того, как оператор открыл тикет. Backend дедуплицирует событие — отправит один раз на каждое новое сообщение визитёра, не на каждый refresh. |
Cookie domain (cross-subdomain identity)
SettingsWidget BuilderConversationCookie domain — поле conversation.cookie_domain. По умолчанию пустое: visitor-session cookie scoped по host, и виджет на example.com и app.example.com создаёт два разных контакта.
Задайте .example.com (с точкой!) — visitor cookie станет cross-subdomain, посетитель сохранит одну беседу при переходе между поддоменами. Точка обязательна; без неё cookie ставится только на указанный хост.
То же самое можно задать через data-cookie-domain атрибут в <script>-теге — атрибут выигрывает у конфига (удобно если стейдж и прод на разных доменах). Подробности про multi-tier storage — в справочнике для разработчиков.
Реакции
Long-press 350ms (на тачах) или hover 600ms (на мышке) по сообщению оператора → всплывает панель из 4 эмодзи. Клик ставит реакцию, счётчик появляется чипом под bubble.
false, панель эмодзи не всплывает, чипы не рендерятся.❤️,🔥,👍,🎉. По умолчанию ❤️ 👍 👎 🎉. Подробнее — в разделе «Бренд».| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
| conversation.reactions_enabled | boolean | true | Master-выключатель. Если false, панель эмодзи не всплывает, чипы не рендерятся. |
| brand.emoji_pack_id | string | — | Свой набор эмодзи через запятую: ❤️,🔥,👍,🎉. По умолчанию ❤️ 👍 👎 🎉. Подробнее — в разделе «Бренд». |
Когда визитёр нажимает реакцию, она моментально появляется у него (optimistic update). Параллельно бэкенд бродкастит событие — message.reaction.added — операторам и другим визитёрам этого тикета (multi-tab support). При получении другие открытые табы ре-фетчат полные счётчики через GET, чтобы порядок добавления/снятия не разъезжался.
Inline keyboards
Оператор может прикрепить под своё сообщение 2D-матрицу кнопок — например, выбор языка, типы запроса, ссылки на документацию. Каждая кнопка — это:
url— открывает ссылку в новой вкладке (window.open(...));deeplink— то же, но для нативных приложений (tg://...,mailto:...);callback— отсылает событие на бэкенд:POST /api/webhooks/widget/{ws}/messages/{id}/inline-callbackс{target}. Бэк создаёт служебное internal message в тикете «Нажата кнопка: target» и шлёт операторам toast с уведомлением.
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
| conversation.inline_keyboard_enabled | boolean | true | Глобально выключить рендеринг inline-keyboard'ов. Сами сообщения остаются, кнопки исчезают. |
System cards
Серые центрированные плашки в ленте для событий тикета. Текст можно переопределить в SettingsWidget BuilderSystem Messages — все поля поддерживают шаблонные подстановки {operator}, {department}, {time}.
{operator}.{time} форматируется в локали посетителя как HH:MM.resolved-событий (визитёр сам нажал «Закрыть»).| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
| ticket_confirmation_text | string | "Тикет создан" | Появляется сразу после первого сообщения визитёра. |
| assigned | { enabled, text } | "Оператор {operator} с вами" | Когда тикет назначен оператору. Backend подставляет имя оператора в {operator}. |
| department_transfer | { enabled, text } | "Передаём в {department}" | Передача между отделами. |
| operator_transfer_text | string | "Передаём другому оператору" | Передача между операторами внутри одного отдела. |
| snoozed | { enabled, text } | "Откладываем до {time}" | Тикет «уснул» до указанного момента. {time} форматируется в локали посетителя как HH:MM. |
| resumed | { enabled, text } | "Возвращаемся к вашему вопросу" | Тикет вернулся в работу из snooze. |
| reopened | { enabled, text } | "Тикет переоткрыт" | Закрытый тикет открыли заново. |
| auto_reply_closed_text | string | — | Что показать, когда тикет был закрыт оператором. Используется и для resolved-событий (визитёр сам нажал «Закрыть»). |
| blocked_reply | { enabled, text } | — | Текст для контактов в чёрном списке. Если включено — посетитель видит, что не может написать; если выключено — UI композера остаётся доступным, но сообщения не отправляются. |
Кнопка «Закрыть тикет»
Если хотите, чтобы посетитель сам мог отметить тикет решённым, задайте hours.close_button_text — между сообщениями и композером появится pill-кнопка с этим текстом. Клик отправляет POST /widget/{ws}/ticket/{tid}/resolve и переводит посетителя на главную.
Edge cases
- Если localStorage визитёра пустой (Safari private mode без сессии) — кнопка покажет inline-error «Не получилось закрыть. Попробуйте ещё раз.» вместо вечного спиннера.
- После закрытия тикета через WS прилетает
ticket.closed→ виджет автоматически рендерит system-card с текстом изsystem_messages.auto_reply_closed_text. - Если у вас включён
conversation.rating— после закрытия визитёр получит prompt с оценкой 1-5 ★.
Прочее
Авто-скролл вниз
Когда посетитель отправляет своё сообщение → виджет всегда прокручивает к низу. Когда приходит входящее по WS → скролл едет к низу, только если визитёр уже у дна. Если он листает старые сообщения, его не дёргает; вместо этого появляется плавающая круглая кнопка ↓ с переходом к последнему сообщению.
Лайтбокс для медиа
Клик по фото или видео в треде открывает их во встроенном лайтбоксе с zoom (mouse wheel) и pan (drag). Esc или клик по фону — закрытие. Тот же UX, что в инбоксе оператора.