diff --git a/CHANGELOG.md b/CHANGELOG.md index cca0898f..26b11a8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,3 +16,7 @@ ratio while filling the element’s entire content box. If the object's aspect ratio does not match the aspect ratio of its box then the object will be clipped to fit. The clipping will be taken from the center. +- `WebChat.toggle()`, `WebChat.open()`, and `WebChat.close` can be used to change the state of the chat box to open or closed. +- `WebChat.show()` and `WebChat.hide()` can be used to show or hide the entire chat widget. +- `WebChat.isOpen()` and `WebChat.isVisible()` can be used to get the open state of the chat box and the visibility state of the entire widget. + diff --git a/README.md b/README.md index 34413d04..4a6a9c78 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,12 @@ About images: `width` and `height` define the size in pixels that images in mess It is recommended to use a particular version (i.e. "webchat-.js") however the file "webchat-latest.js" is also available and is updated continuously with the latest version. +`WebChat.toggle()`, `WebChat.open()`, and `WebChat.close` can be used to change the state of the chat box to open or closed. + +`WebChat.show()` and `WebChat.hide()` can be used to show or hide the entire chat widget. + +`WebChat.isOpen()` and `WebChat.isVisible()` can be used to get the open state of the chat box and the visibility state of the entire widget. + #### As a React component Install the package from GitHub by running: @@ -64,7 +70,7 @@ function CustomWidget = () => { interval={2000} initPayload={"/get_started"} socketUrl={"http://localhost:5500"} - socketPath={"/socket.io/"} + socketPath={"/socket.io/"} title={"Title"} embedded={true} params={ diff --git a/dev/src/index.html b/dev/src/index.html index 9a91413d..24d2729e 100644 --- a/dev/src/index.html +++ b/dev/src/index.html @@ -24,7 +24,6 @@ } }) - diff --git a/index.js b/index.js index 20b14659..f1b5e5d3 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,10 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { Widget } from './index_for_react_app'; +import { Widget, toggleWidget, openWidget, closeWidget, showWidget, hideWidget, isOpen, isVisible } from './index_for_react_app'; const plugin = { init: (args) => { + ReactDOM.render( , document.querySelector(args.selector) - ); } }; export { plugin as default, - Widget + Widget, + toggleWidget as toggle, + openWidget as open, + closeWidget as close, + showWidget as show, + hideWidget as hide, + isOpen, + isVisible }; diff --git a/index_for_react_app.js b/index_for_react_app.js index 452dc32a..02df0b06 100644 --- a/index_for_react_app.js +++ b/index_for_react_app.js @@ -7,7 +7,13 @@ import { addImageSnippet, addQuickReply, renderCustomComponent, + isOpen, + isVisible, + showWidget, + hideWidget, toggleWidget, + openWidget, + closeWidget, toggleInputDisabled, dropMessages } from './src/store/actions/dispatcher'; @@ -21,7 +27,13 @@ export { addImageSnippet, addQuickReply, renderCustomComponent, + isOpen, + isVisible, + showWidget, + hideWidget, toggleWidget, + openWidget, + closeWidget, toggleInputDisabled, dropMessages }; diff --git a/src/components/Widget/index.js b/src/components/Widget/index.js index bb3b4896..e436398b 100644 --- a/src/components/Widget/index.js +++ b/src/components/Widget/index.js @@ -103,6 +103,7 @@ class Widget extends Component { profileAvatar={this.props.profileAvatar} showCloseButton={this.props.showCloseButton} fullScreenMode={this.props.fullScreenMode} + showWidget={this.props.showWidget} showChat={this.props.showChat} badge={this.props.badge} embedded={this.props.embedded} @@ -126,6 +127,7 @@ Widget.propTypes = { profileAvatar: PropTypes.string, showCloseButton: PropTypes.bool, fullScreenMode: PropTypes.bool, + showWidget: PropTypes.bool, showChat: PropTypes.bool, badge: PropTypes.number, socket: PropTypes.shape({}), diff --git a/src/components/Widget/layout.js b/src/components/Widget/layout.js index 4379f1cc..0c0e3f17 100644 --- a/src/components/Widget/layout.js +++ b/src/components/Widget/layout.js @@ -16,6 +16,7 @@ const WidgetLayout = (props) => { ); return ( + props.showWidget ?
{ (props.fullScreenMode || props.showChat || props.embedded) && @@ -39,6 +40,7 @@ const WidgetLayout = (props) => { /> }
+ : null ); }; @@ -58,6 +60,7 @@ WidgetLayout.propTypes = { }; export default connect(store => ({ + showWidget: store.behavior.get('showWidget'), showChat: store.behavior.get('showChat'), disabledInput: store.behavior.get('disabledInput') }))(WidgetLayout); diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js index 821ac96d..0ffe7ba8 100644 --- a/src/store/actions/actionTypes.js +++ b/src/store/actions/actionTypes.js @@ -1,5 +1,11 @@ export const INITIALIZE = 'INITIALIZE'; +export const GET_OPEN_STATE = 'GET_OPEN_STATE'; +export const GET_VISIBLE_STATE = 'GET_VISIBLE_STATE'; +export const SHOW_WIDGET = 'SHOW_WIDGET'; +export const HIDE_WIDGET = 'HIDE_WIDGET'; export const TOGGLE_CHAT = 'TOGGLE_CHAT'; +export const OPEN_CHAT = 'OPEN_CHAT'; +export const CLOSE_CHAT = 'CLOSE_CHAT'; export const TOGGLE_INPUT_DISABLED = 'TOGGLE_INPUT_DISABLED'; export const CHANGE_INPUT_FIELD_HINT = 'CHANGE_INOUT_FIELD_HINT'; export const ADD_NEW_USER_MESSAGE = 'ADD_NEW_USER_MESSAGE'; diff --git a/src/store/actions/dispatcher.js b/src/store/actions/dispatcher.js index 4d9e5d32..63291367 100644 --- a/src/store/actions/dispatcher.js +++ b/src/store/actions/dispatcher.js @@ -1,6 +1,14 @@ import { store } from '../store'; import * as actions from './index'; +export function isOpen() { + return store.dispatch(actions.getOpenState()); + } + +export function isVisible() { + return store.dispatch(actions.getVisibleState()); +} + export function initialize() { store.dispatch(actions.initialize()); } @@ -45,10 +53,26 @@ export function renderCustomComponent(component, props, showAvatar = false) { store.dispatch(actions.renderCustomComponent(component, props, showAvatar)); } +export function showWidget() { + store.dispatch(actions.showWidget()); +} + +export function hideWidget() { + store.dispatch(actions.hideWidget()); +} + export function toggleWidget() { store.dispatch(actions.toggleChat()); } +export function openWidget() { + store.dispatch(actions.openChat()); +} + +export function closeWidget() { + store.dispatch(actions.closeChat()); +} + export function toggleInputDisabled() { store.dispatch(actions.toggleInputDisabled()); } diff --git a/src/store/actions/index.js b/src/store/actions/index.js index c9c90ad3..841f02be 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -6,12 +6,48 @@ export function initialize() { }; } +export function getOpenState() { + return { + type: actions.GET_OPEN_STATE + }; +} + +export function getVisibleState() { + return { + type: actions.GET_VISIBLE_STATE + }; +} + +export function showWidget() { + return { + type: actions.SHOW_WIDGET + }; +} + +export function hideWidget() { + return { + type: actions.HIDE_WIDGET + }; +} + export function toggleChat() { return { type: actions.TOGGLE_CHAT }; } +export function openChat() { + return { + type: actions.OPEN_CHAT + }; +} + +export function closeChat() { + return { + type: actions.CLOSE_CHAT + }; +} + export function toggleInputDisabled() { return { type: actions.TOGGLE_INPUT_DISABLED diff --git a/src/store/reducers/behaviorReducer.js b/src/store/reducers/behaviorReducer.js index 536cb3e5..911232e7 100644 --- a/src/store/reducers/behaviorReducer.js +++ b/src/store/reducers/behaviorReducer.js @@ -2,13 +2,25 @@ import { Map } from 'immutable'; import * as actionTypes from '../actions/actionTypes'; export default function (inputFieldTextHint) { - const initialState = Map({ initialized: false, showChat: false, disabledInput: false, inputFieldTextHint }); + const initialState = Map({ initialized: false, showWidget: true, showChat: false, disabledInput: false, inputFieldTextHint }); return function reducer(state = initialState, action) { switch (action.type) { + case actionTypes.SHOW_WIDGET: { + return state.update('showWidget', showWidget => true); + } + case actionTypes.HIDE_WIDGET: { + return state.update('showWidget', showWidget => false); + } case actionTypes.TOGGLE_CHAT: { return state.update('showChat', showChat => !showChat); } + case actionTypes.OPEN_CHAT: { + return state.update('showChat', showChat => true); + } + case actionTypes.CLOSE_CHAT: { + return state.update('showChat', showChat => false); + } case actionTypes.TOGGLE_INPUT_DISABLED: { return state.update('disabledInput', disabledInput => !disabledInput); } diff --git a/src/store/store.js b/src/store/store.js index d6f4f596..cba1fda4 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -2,14 +2,24 @@ import { createStore, combineReducers, applyMiddleware } from "redux"; import behavior from "./reducers/behaviorReducer"; import messages from "./reducers/messagesReducer"; +import * as actionTypes from './actions/actionTypes'; let store = "call initStore first"; function initStore(hint, socket) { const customMiddleWare = (store) => next => (action) => { - if (action.type === "EMIT_NEW_USER_MESSAGE") { - socket.emit("user_uttered", { message: action.text, customData: socket.customData }); + switch (action.type) { + case actionTypes.EMIT_NEW_USER_MESSAGE: { + socket.emit("user_uttered", { message: action.text, customData: socket.customData }); + } + case actionTypes.GET_OPEN_STATE: { + return store.getState().behavior.get("showChat"); + } + case actionTypes.GET_VISIBLE_STATE: { + return store.getState().behavior.get("showWidget"); + } } + // console.log('Middleware triggered:', action); next(action); };