Skip to content

Commit

Permalink
feat(webchat): allow to react on message click (#521)
Browse files Browse the repository at this point in the history
* feat(webchat): allow to react on message click

* remove console.log

* fix build

* remove console.log
  • Loading branch information
laurentlp committed Aug 10, 2022
1 parent 9546369 commit ace6d45
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 32 deletions.
38 changes: 34 additions & 4 deletions packages/webchat/src/components/messages/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { WrappedComponentProps, injectIntl } from 'react-intl'

import { RootStore, StoreDef } from '../../store'
import { Renderer } from '../../typings'
import { postMessageToParent } from '../../utils/webchatEvents'

class Message extends Component<MessageProps> {
state = {
Expand All @@ -25,6 +26,22 @@ class Message extends Component<MessageProps> {
)
}

onMessageClick = () => {
this.props.store?.setSelectedMessage(this.props.messageId!)

postMessageToParent(
'messageClicked',
{
id: this.props.messageId,
conversationId: this.props.store?.currentConversationId,
sentOn: this.props.sentOn,
payload: { ...this.props.payload },
from: this.props.isBotMessage ? 'bot' : 'user'
},
this.props.store?.config.chatId
)
}

render() {
if (this.state.hasError) {
return '* Cannot display message *'
Expand Down Expand Up @@ -64,9 +81,17 @@ class Message extends Component<MessageProps> {

const additionalStyle = (this.props.payload && this.props.payload['web-style']) || {}

const messageSelectedClass = {
'bpw-message-selected': this.props.selectedMessageId === this.props.messageId
}

if (this.props.noBubble || this.props.payload?.wrapped?.noBubble) {
return (
<div className={classnames(this.props.className, wrappedClass)} style={additionalStyle}>
<div
className={classnames(this.props.className, wrappedClass, messageSelectedClass)}
style={additionalStyle}
onClick={this.onMessageClick}
>
{rendered}
</div>
)
Expand All @@ -79,7 +104,11 @@ class Message extends Component<MessageProps> {
tabIndex={-1}
style={additionalStyle}
>
<div tabIndex={-1} className="bpw-chat-bubble-content">
<div
tabIndex={-1}
className={classnames('bpw-chat-bubble-content', messageSelectedClass)}
onClick={this.onMessageClick}
>
<span className="sr-only">
{this.props.store!.intl.formatMessage({
id: this.props.isBotMessage ? 'message.botSaid' : 'message.iSaid',
Expand All @@ -96,7 +125,8 @@ class Message extends Component<MessageProps> {
}

export default inject(({ store }: { store: RootStore }) => ({
intl: store.intl
intl: store.intl,
selectedMessageId: store.selectedMessageId
}))(injectIntl(observer(Message)))

type MessageProps = Renderer.Message & WrappedComponentProps & Pick<StoreDef, 'intl'>
type MessageProps = Renderer.Message & WrappedComponentProps & Pick<StoreDef, 'intl' | 'selectedMessageId'>
13 changes: 10 additions & 3 deletions packages/webchat/src/components/messages/MessageGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,13 @@ class MessageGroup extends React.Component<Props> {
>
{avatar}
<div role="region" className={'bpw-message-container'}>
<div aria-live="assertive" role="log" className={'bpw-message-group'}>
<div
aria-live="assertive"
role="log"
className={classnames('bpw-message-group', {
'bpw-message-group-selected': !!this.props.messages.find((m) => m.id === this.props.selectedMessageId)
})}
>
<span data-from={fromLabel} className="from hidden" aria-hidden="true">
{fromLabel}
</span>
Expand Down Expand Up @@ -96,7 +102,8 @@ class MessageGroup extends React.Component<Props> {
export default inject(({ store }: { store: RootStore }) => ({
store,
sendFeedback: store.sendFeedback,
sendData: store.sendData
sendData: store.sendData,
selectedMessageId: store.selectedMessageId
}))(MessageGroup)

type Props = {
Expand All @@ -105,4 +112,4 @@ type Props = {
messages: MessageDetails[]
isLastGroup: boolean
store?: RootStore
} & Pick<StoreDef, 'sendFeedback' | 'sendData'>
} & Pick<StoreDef, 'sendFeedback' | 'sendData' | 'selectedMessageId'>
7 changes: 2 additions & 5 deletions packages/webchat/src/core/socket.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Message, MessagingSocket, UserCredentials } from '@botpress/messaging-socket'
import { Config } from '../typings'
import { postMessageToParent } from '../utils/webchatEvents'

export default class BpSocket {
public socket: MessagingSocket
Expand All @@ -24,10 +25,6 @@ export default class BpSocket {
return message
}

public postToParent = (_type: string, payload: any) => {
window.parent?.postMessage({ ...payload, chatId: this.chatId }, '*')
}

public async connect(): Promise<void> {
const creds = this.getCreds()
await this.socket.connect(creds)
Expand All @@ -36,7 +33,7 @@ export default class BpSocket {
const userId = this.socket.userId!
window.BP_STORAGE.set('creds', this.socket.creds)

this.postToParent('', { userId })
postMessageToParent('userConnected', { userId }, this.chatId)
}
}

Expand Down
11 changes: 4 additions & 7 deletions packages/webchat/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { RootStore, StoreDef } from './store'
import { Config, Message } from './typings'
import { isIE } from './utils'
import { initializeAnalytics, trackMessage, trackWebchatState } from './utils/analytics'
import { postMessageToParent } from './utils/webchatEvents'

export const DEFAULT_TYPING_DELAY = 1000

Expand Down Expand Up @@ -102,7 +103,7 @@ class Web extends React.Component<MainProps> {
}

if (this.config.containerWidth) {
this.postMessageToParent('setWidth', this.config.containerWidth)
postMessageToParent('setWidth', this.config.containerWidth, this.config.chatId)
}

await this.props.fetchBotInfo!()
Expand All @@ -114,10 +115,6 @@ class Web extends React.Component<MainProps> {
this.setupObserver()
}

postMessageToParent(type: string, value: any) {
window.parent?.postMessage({ type, value, chatId: this.config.chatId }, '*')
}

extractConfig(): Config {
let userConfig = Object.assign({}, constants.DEFAULT_CONFIG, this.props.config)
const { options } = queryString.parse(location.search)
Expand Down Expand Up @@ -150,7 +147,7 @@ class Web extends React.Component<MainProps> {
setupObserver() {
observe(this.props.dimensions!, 'container', (data) => {
if (data.newValue) {
this.postMessageToParent('setWidth', data.newValue)
postMessageToParent('setWidth', data.newValue, this.config.chatId)
}
})
}
Expand Down Expand Up @@ -295,7 +292,7 @@ class Web extends React.Component<MainProps> {
})

if (this.parentClass !== parentClass) {
this.postMessageToParent('setClass', parentClass)
postMessageToParent('setClass', parentClass, this.config.chatId)
this.parentClass = parentClass
}

Expand Down
19 changes: 11 additions & 8 deletions packages/webchat/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
} from '../typings'
import { downloadFile } from '../utils'
import { trackMessage } from '../utils/analytics'
import { postMessageToParent } from '../utils/webchatEvents'

import ComposerStore from './composer'
import ViewStore from './view'
Expand All @@ -41,6 +42,9 @@ class RootStore {
@observable
public currentConversation?: CurrentConversation

@observable
public selectedMessageId?: string

@observable
public botInfo!: BotInfo

Expand Down Expand Up @@ -86,6 +90,11 @@ class RootStore {
this.api = new WebchatApi(socket)
}

@action.bound
setSelectedMessage(messageId: string) {
this.selectedMessageId = messageId
}

@computed
get isConversationStarted(): boolean {
return !!this.currentConversation?.messages.length
Expand Down Expand Up @@ -126,12 +135,6 @@ class RootStore {
return this.currentConversation?.id
}

@action.bound
postMessage(name: string, payload?: any) {
const chatId = this.config.chatId
window.parent.postMessage({ name, chatId, payload }, '*')
}

@action.bound
updateMessages(messages: Message[]) {
if (this.currentConversation) {
Expand Down Expand Up @@ -217,7 +220,7 @@ class RootStore {
await this.fetchConversation()
runInAction('-> setInitialized', () => {
this.isInitialized = true
this.postMessage('webchatReady')
postMessageToParent('webchatReady', undefined, this.config.chatId)
})
} catch (err) {
console.error('Error while fetching data, creating new conversation...', err)
Expand Down Expand Up @@ -464,7 +467,7 @@ class RootStore {

@action.bound
publishConfigChanged() {
this.postMessage('configChanged', JSON.stringify(this.config, undefined, 2))
postMessageToParent('configChanged', { ...this.config }, this.config.chatId)
}

@action.bound
Expand Down
11 changes: 6 additions & 5 deletions packages/webchat/src/store/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { action, computed, observable, runInAction } from 'mobx'
import constants from '../core/constants'
import { ChatDimensions, CustomAction, CustomButton } from '../typings'

import { postMessageToParent } from '../utils/webchatEvents'
import { RootStore } from '.'

class ViewStore {
Expand Down Expand Up @@ -179,7 +180,7 @@ class ViewStore {
@action.bound
setLoadingCompleted() {
this._isLoading = false
this.rootStore.postMessage('webchatLoaded')
postMessageToParent('webchatLoaded', undefined, this.rootStore.config.chatId)
}

@action.bound
Expand Down Expand Up @@ -247,7 +248,7 @@ class ViewStore {
showChat() {
if (this.disableAnimations) {
this.activeView = 'side'
this.rootStore.postMessage('webchatOpened')
postMessageToParent('webchatOpened', undefined, this.rootStore.config.chatId)
return this._updateTransitions({ widgetTransition: undefined, sideTransition: 'none' })
}

Expand All @@ -259,7 +260,7 @@ class ViewStore {

this._endAnimation('side')

this.rootStore.postMessage('webchatOpened')
postMessageToParent('webchatOpened', undefined, this.rootStore.config.chatId)
}

@action.bound
Expand All @@ -270,7 +271,7 @@ class ViewStore {

if (this.disableAnimations) {
this.activeView = 'widget'
this.rootStore.postMessage('webchatClosed')
postMessageToParent('webchatClosed', undefined, this.rootStore.config.chatId)
return this._updateTransitions({ widgetTransition: undefined, sideTransition: undefined })
}

Expand All @@ -284,7 +285,7 @@ class ViewStore {

this._endAnimation('widget')

this.rootStore.postMessage('webchatClosed')
postMessageToParent('webchatClosed', undefined, this.rootStore.config.chatId)
}

@action.bound
Expand Down
3 changes: 3 additions & 0 deletions packages/webchat/src/utils/webchatEvents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const postMessageToParent = (type: string, value: any, chatId?: string) => {
window.parent?.postMessage({ type, value, chatId }, '*')
}

0 comments on commit ace6d45

Please sign in to comment.