diff --git a/README.md b/README.md index f4a2612f2..a24868a10 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ class App extends Component { export default App; ``` -4- Customize the widget to match your app design! You can add both props to manage the title of the widget, the avatar it will use and of course, you can change, from the CSS, the styles the widget will have. +4- Customize the widget to match your app design! You can add both props to manage the title of the widget and the avatar it will use. Of course, feel free to change the styles the widget will have in the CSS ```js import React, { Component } from 'react'; @@ -141,11 +141,12 @@ export default App; #### Props +- **handleNewUserMessage:** (PropTypes.func.isRequired) Function to handle the user input, will receive the full text message when submitted - **title:** (PropTypes.string) Title of the widget - **subtitle:** (PropTypes.string) Subtitle of the widget - **senderPlaceHolder:** (PropTypes.string) The placeholder of the message input -- **profileAvatar:** (PropTypes.string.isRequired) The profile image that will be set on the responses -- **handleNewUserMessage:** (PropTypes.func.isRequired) Function to handle the user input, will receive the full text message when submitted +- **profileAvatar:** (PropTypes.string) The profile image that will be set on the responses +- **showCloseButton:** (PropTypes.bool) Show or hide the close button in full screen mode #### Styles @@ -198,6 +199,18 @@ In order to add new messages, you are provided with the following methods: **Markdown is supported for the responses and user messages.** +#### Widget behavior + +You can also control certain actions of the widget: + +- **toggleWidget** + - params: No params expected + - This method is to toggle the widget at will without the need to trigger the click event on the launcher + +- **toggleInputDisabled** + - params: No params expected + - Method to toggle the availability of the message input for the user to write on + ## About This project is maintained by [Martín Callegari](https://github.com/mcallegari10) and it was written by [Wolox](http://www.wolox.com.ar). diff --git a/index.js b/index.js index 220cfe88e..c7a7d91cb 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,8 @@ import { addResponseMessage, addLinkSnippet, renderCustomComponent, - toggleWidget + toggleWidget, + toggleInputDisabled } from './src/store/actions/dispatcher'; export { @@ -13,5 +14,6 @@ export { addResponseMessage, addLinkSnippet, renderCustomComponent, - toggleWidget + toggleWidget, + toggleInputDisabled }; diff --git a/src/components/Widget/components/Conversation/components/Header/index.js b/src/components/Widget/components/Conversation/components/Header/index.js index 0a161494c..a29aaf24d 100644 --- a/src/components/Widget/components/Conversation/components/Header/index.js +++ b/src/components/Widget/components/Conversation/components/Header/index.js @@ -1,17 +1,26 @@ import React from 'react'; import PropTypes from 'prop-types'; +import close from 'assets/clear-button.svg'; import './style.scss'; -const Header = ({ title, subtitle }) => +const Header = ({ title, subtitle, toggleChat, showCloseButton }) =>
+ { + showCloseButton && + + }

{title}

{subtitle}
; Header.propTypes = { title: PropTypes.string, - subtitle: PropTypes.string + subtitle: PropTypes.string, + toggleChat: PropTypes.func, + showCloseButton: PropTypes.bool }; export default Header; diff --git a/src/components/Widget/components/Conversation/components/Header/style.scss b/src/components/Widget/components/Conversation/components/Header/style.scss index 28774a049..959cd5834 100644 --- a/src/components/Widget/components/Conversation/components/Header/style.scss +++ b/src/components/Widget/components/Conversation/components/Header/style.scss @@ -1,15 +1,48 @@ @import "variables.scss"; .header { - text-align: center; background-color: $turqois-1; border-radius: 10px 10px 0 0; color: $white; + display: flex; + flex-direction: column; + text-align: center; padding: 15px 0 25px; +} + +.title { + font-size: 24px; + margin: 0; + padding: 15px 0; +} + +.close-button { + display: none; +} + +@media screen and (max-width: 800px) { + .header { + border-radius: 0; + flex-shrink: 0; + position: relative; + } .title { - font-size: 24px; - margin: 0; - padding: 15px; + padding: 0 0 15px 0; + } + + .close-button { + background-color: $turqois-1; + border: 0; + display: block; + position: absolute; + right: 10px; + top: 20px; + width: 40px; + } + + .close { + width: 20px; + height: 20px; } } diff --git a/src/components/Widget/components/Conversation/components/Messages/components/Snippet/index.js b/src/components/Widget/components/Conversation/components/Messages/components/Snippet/index.js index c2d5a3cf2..4d19aadd4 100644 --- a/src/components/Widget/components/Conversation/components/Messages/components/Snippet/index.js +++ b/src/components/Widget/components/Conversation/components/Messages/components/Snippet/index.js @@ -8,11 +8,11 @@ class Snippet extends PureComponent { return (
- {this.props.message.get('title')} + { this.props.message.get('title') }
- {this.props.message.get('link')} + { this.props.message.get('link') }
diff --git a/src/components/Widget/components/Conversation/components/Messages/index.js b/src/components/Widget/components/Conversation/components/Messages/index.js index e56002de5..5dc5df3e0 100644 --- a/src/components/Widget/components/Conversation/components/Messages/index.js +++ b/src/components/Widget/components/Conversation/components/Messages/index.js @@ -30,14 +30,19 @@ class Messages extends Component { render() { return (
- {this.props.messages.map((message, index) => -
- {message.get('showAvatar') && - profile - } - { this.getComponentToRender(message) } -
- )} + { + this.props.messages.map((message, index) => +
+ { + message.get('showAvatar') && + profile + } + { + this.getComponentToRender(message) + } +
+ ) + }
); } diff --git a/src/components/Widget/components/Conversation/components/Messages/styles.scss b/src/components/Widget/components/Conversation/components/Messages/styles.scss index 2408c3a48..d8ab92642 100644 --- a/src/components/Widget/components/Conversation/components/Messages/styles.scss +++ b/src/components/Widget/components/Conversation/components/Messages/styles.scss @@ -7,3 +7,10 @@ overflow-y: scroll; padding-top: 10px; } + +@media screen and (max-width: 800px) { + .messages-container { + height: 100%; + max-height: none; + } +} diff --git a/src/components/Widget/components/Conversation/components/Sender/index.js b/src/components/Widget/components/Conversation/components/Sender/index.js index e82ed92ca..62ed7b862 100644 --- a/src/components/Widget/components/Conversation/components/Sender/index.js +++ b/src/components/Widget/components/Conversation/components/Sender/index.js @@ -1,11 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; + import send from 'assets/send_button.svg'; import './style.scss'; -const Sender = ({ sendMessage, placeholder }) => +const Sender = ({ sendMessage, placeholder, disabledInput }) =>
- + @@ -13,7 +14,8 @@ const Sender = ({ sendMessage, placeholder }) => Sender.propTypes = { sendMessage: PropTypes.func, - placeholder: PropTypes.string + placeholder: PropTypes.string, + disabledInput: PropTypes.bool }; export default Sender; diff --git a/src/components/Widget/components/Conversation/components/Sender/style.scss b/src/components/Widget/components/Conversation/components/Sender/style.scss index 7f54e4d52..a9fb5abb2 100644 --- a/src/components/Widget/components/Conversation/components/Sender/style.scss +++ b/src/components/Widget/components/Conversation/components/Sender/style.scss @@ -1,6 +1,7 @@ @import "variables.scss"; .sender { + align-items: center; display: flex; background-color: $grey-2; height: 45px; @@ -11,7 +12,6 @@ .new-message { width: 100%; border: 0; - align-self: center; background-color: $grey-2; height: 30px; padding-left: 15px; @@ -29,3 +29,10 @@ height: 25px; } } + +@media screen and (max-width: 800px) { + .sender { + border-radius: 0; + flex-shrink: 0; + } +} diff --git a/src/components/Widget/components/Conversation/index.js b/src/components/Widget/components/Conversation/index.js index ec6f7c1f9..40ca40a42 100644 --- a/src/components/Widget/components/Conversation/index.js +++ b/src/components/Widget/components/Conversation/index.js @@ -11,6 +11,8 @@ const Conversation = props =>
; @@ -26,14 +29,10 @@ Conversation.propTypes = { subtitle: PropTypes.string, sendMessage: PropTypes.func, senderPlaceHolder: PropTypes.string, - profileAvatar: PropTypes.string -}; - -Conversation.defaultProps = { - headerStyles: {}, - messageStyles: {}, - responsesStyles: {}, - snippetStyles: {} + profileAvatar: PropTypes.string, + toggleChat: PropTypes.func, + showCloseButton: PropTypes.bool, + disabledInput: PropTypes.bool }; export default Conversation; diff --git a/src/components/Widget/components/Conversation/style.scss b/src/components/Widget/components/Conversation/style.scss index 69a1b9805..3c283dce8 100644 --- a/src/components/Widget/components/Conversation/style.scss +++ b/src/components/Widget/components/Conversation/style.scss @@ -10,3 +10,11 @@ .slide-out { @include animation(0, 0.5s, slide-out); } + +@media screen and (max-width: 800px) { + .conversation-container { + display: flex; + flex-direction: column; + height: 100%; + } +} diff --git a/src/components/Widget/components/Launcher/index.js b/src/components/Widget/components/Launcher/index.js index 3d681a06f..4ee408c6f 100644 --- a/src/components/Widget/components/Launcher/index.js +++ b/src/components/Widget/components/Launcher/index.js @@ -7,10 +7,11 @@ import close from 'assets/clear-button.svg'; import './style.scss'; const Launcher = ({ toggle, chatOpened }) => - ; diff --git a/src/components/Widget/components/Launcher/style.scss b/src/components/Widget/components/Launcher/style.scss index e18ab4d6b..5f9429678 100644 --- a/src/components/Widget/components/Launcher/style.scss +++ b/src/components/Widget/components/Launcher/style.scss @@ -25,3 +25,16 @@ width: 20px; @include animation(0, 0.5s, rotation-lr); } + +@media screen and (max-width: 800px){ + .launcher { + bottom: 0; + margin: 20px; + position: fixed; + right: 0; + } + + .hide-sm { + display: none; + } +} diff --git a/src/components/Widget/index.js b/src/components/Widget/index.js index f6b507744..56e6cc561 100644 --- a/src/components/Widget/index.js +++ b/src/components/Widget/index.js @@ -29,23 +29,26 @@ class Widget extends Component { subtitle={this.props.subtitle} senderPlaceHolder={this.props.senderPlaceHolder} profileAvatar={this.props.profileAvatar} + showCloseButton={this.props.showCloseButton} /> ); } } Widget.propTypes = { + handleNewUserMessage: PropTypes.func.isRequired, title: PropTypes.string, subtitle: PropTypes.string, - handleNewUserMessage: PropTypes.func.isRequired, senderPlaceHolder: PropTypes.string, - profileAvatar: PropTypes.string + profileAvatar: PropTypes.string, + showCloseButton: PropTypes.bool }; Widget.defaultProps = { title: 'Welcome', subtitle: 'This is your chat subtitle', - senderPlaceHolder: 'Type a message...' + senderPlaceHolder: 'Type a message...', + showCloseButton: true }; export default connect()(Widget); diff --git a/src/components/Widget/layout.js b/src/components/Widget/layout.js index ec810d049..c988de969 100644 --- a/src/components/Widget/layout.js +++ b/src/components/Widget/layout.js @@ -8,13 +8,18 @@ import './style.scss'; const WidgetLayout = props =>
- {props.showChat && + { + props.showChat && } ({ - showChat: store.behavior.get('showChat') + showChat: store.behavior.get('showChat'), + disabledInput: store.behavior.get('disabledInput') }))(WidgetLayout); diff --git a/src/components/Widget/style.scss b/src/components/Widget/style.scss index d094d2428..02a9b4dc8 100644 --- a/src/components/Widget/style.scss +++ b/src/components/Widget/style.scss @@ -11,3 +11,12 @@ width: 90vw; z-index: 9999; } + +@media screen and (max-width: 800px) { + .widget-container { + height: 100%; + margin: 0; + max-width: none; + width: 100%; + } +} diff --git a/src/index.js b/src/index.js index 699b359cd..85cf6df3a 100644 --- a/src/index.js +++ b/src/index.js @@ -13,6 +13,7 @@ const ConnectedWidget = props => handleNewUserMessage={props.handleNewUserMessage} senderPlaceHolder={props.senderPlaceHolder} profileAvatar={props.profileAvatar} + showCloseButton={props.showCloseButton} /> ; @@ -21,7 +22,8 @@ ConnectedWidget.propTypes = { subtitle: PropTypes.string, handleNewUserMessage: PropTypes.func.isRequired, senderPlaceHolder: PropTypes.string, - profileAvatar: PropTypes.string + profileAvatar: PropTypes.string, + showCloseButton: PropTypes.bool }; export default ConnectedWidget; diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js index ad0498894..b55739a0f 100644 --- a/src/store/actions/actionTypes.js +++ b/src/store/actions/actionTypes.js @@ -1,4 +1,5 @@ export const TOGGLE_CHAT = 'TOGGLE_CHAT'; +export const TOGGLE_INPUT_DISABLED = 'TOGGLE_INPUT_DISABLED'; export const ADD_NEW_USER_MESSAGE = 'ADD_NEW_USER_MESSAGE'; export const ADD_NEW_RESPONSE_MESSAGE = 'ADD_NEW_RESPONSE_MESSAGE'; export const ADD_NEW_LINK_SNIPPET = 'ADD_NEW_LINK_SNIPPET'; diff --git a/src/store/actions/dispatcher.js b/src/store/actions/dispatcher.js index 8347d25c1..2b1a47281 100644 --- a/src/store/actions/dispatcher.js +++ b/src/store/actions/dispatcher.js @@ -20,3 +20,7 @@ export function renderCustomComponent(component, props) { export function toggleWidget() { store.dispatch(actions.toggleChat()); } + +export function toggleInputDisabled() { + store.dispatch(actions.toggleInputDisabled()); +} diff --git a/src/store/actions/index.js b/src/store/actions/index.js index 38b7b0f88..937b42bdb 100644 --- a/src/store/actions/index.js +++ b/src/store/actions/index.js @@ -6,6 +6,12 @@ export function toggleChat() { }; } +export function toggleInputDisabled() { + return { + type: actions.TOGGLE_INPUT_DISABLED + }; +} + export function addUserMessage(text) { return { type: actions.ADD_NEW_USER_MESSAGE, diff --git a/src/store/reducers/behaviorReducer.js b/src/store/reducers/behaviorReducer.js index 3c7051918..7d1204029 100644 --- a/src/store/reducers/behaviorReducer.js +++ b/src/store/reducers/behaviorReducer.js @@ -1,13 +1,16 @@ import { Map } from 'immutable'; import * as actionTypes from '../actions/actionTypes'; -const initialState = Map({ showChat: false }); +const initialState = Map({ showChat: false, disabledInput: false }); export default function reducer(state = initialState, action) { switch (action.type) { case actionTypes.TOGGLE_CHAT: { return state.update('showChat', showChat => !showChat); } + case actionTypes.TOGGLE_INPUT_DISABLED: { + return state.update('disabledInput', disabledInput => !disabledInput); + } default: return state; }