diff --git a/js-miniapp-sample/src/pages/chatbot.js b/js-miniapp-sample/src/pages/chatbot.js deleted file mode 100644 index d0bce6d6b..000000000 --- a/js-miniapp-sample/src/pages/chatbot.js +++ /dev/null @@ -1,189 +0,0 @@ -import React, { useState, Fragment } from 'react'; - -import { - makeStyles, - FormControl, - InputLabel, - Select, - MenuItem, - CardContent, - CardActions, - Button, - TextField, - Dialog, - DialogTitle, - DialogContent, - DialogContentText, - DialogActions, -} from '@material-ui/core'; -import { connect } from 'react-redux'; - -import { getBotsList } from '../services/chatbot/actions'; -import type { ChatBot } from '../services/chatbot/types'; -import GreyCard from '../components/GreyCard'; - -const useStyles = makeStyles((theme) => ({ - formControl: { - margin: theme.spacing(1), - minWidth: '100%', - }, - fields: { - color: theme.color.primary, - '& div': { - color: theme.color.primary, - }, - }, - content: { - height: '50%', - justifyContent: 'center', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - fontSize: 18, - fontWeight: 'bold', - }, - actions: { - justifyContent: 'center', - }, - errorMessage: { - fontSize: 12, - color: 'indianred', - }, -})); - -type ChatBotProps = { - bots: Array, -}; - -const TalkToChatBot = (props: ChatBotProps) => { - const classes = useStyles(); - const chatbots = props.bots; - const [chatbot, setChatbot] = useState({ - id: chatbots[0] !== undefined ? chatbots[0].id : -1, - message: '', - }); - const [validation, setValidationState] = useState({ - error: false, - message: '', - }); - const [chatbotMessage, setChatbotMessage] = useState({ show: false }); - const validate = () => { - if ( - chatbots.map((it) => it.id).findIndex((it) => it === chatbot.id) === -1 - ) { - setValidationState({ error: true, message: 'select chatbot' }); - return false; - } else if ( - chatbot.message === undefined || - chatbot.message.trim().length === 0 - ) { - setValidationState({ error: true, message: 'enter message to chatbot' }); - return false; - } else { - setValidationState({ error: false, message: '' }); - } - return true; - }; - const handleChange = (event) => { - setChatbot({ ...chatbot, id: event.target.value }); - }; - const talkToChatbot = () => { - if (validate()) { - setChatbotMessage({ show: true }); - } - }; - - const onMessageToChatbotChange = (event) => { - setChatbot({ ...chatbot, message: event.target.value }); - }; - - const onChatbotClose = () => { - setChatbotMessage({ show: false }); - }; - return ( - - - - - Chatbot - - - - - - {validation.error && ( -
- {validation.message} -
- )} -
- - - -
- - - Chatbot Response - - Hello - - - - - -
- ); -}; - -const mapStatetoProps = (state, props) => { - return { - ...props, - bots: state.chatbot.bots, - }; -}; -const mapDispatchToProps = (dispatch) => { - return { - getBots: () => dispatch(getBotsList()), - }; -}; - -export default connect(mapStatetoProps, mapDispatchToProps)(TalkToChatBot); diff --git a/js-miniapp-sample/src/pages/message.js b/js-miniapp-sample/src/pages/message.js new file mode 100644 index 000000000..374d6d8a7 --- /dev/null +++ b/js-miniapp-sample/src/pages/message.js @@ -0,0 +1,246 @@ +import React, { useState, Fragment } from 'react'; + +import { + makeStyles, + FormControl, + InputLabel, + Select, + MenuItem, + CardActions, + Button, + TextField, + Dialog, + DialogTitle, + DialogContent, + DialogContentText, + DialogActions, +} from '@material-ui/core'; +import { connect } from 'react-redux'; +import { sendMessageToContact } from '../services/message/actions'; + +import { getMessageTypeList } from '../services/message/actions'; +import type { MessageType } from '../services/message/types'; + +const useStyles = makeStyles((theme) => ({ + formControl: { + margin: theme.spacing(1), + minWidth: '100%', + }, + fields: { + color: theme.color.primary, + '& div': { + color: theme.color.primary, + }, + }, + actions: { + justifyContent: 'center', + }, + errorMessage: { + fontSize: 12, + color: 'indianred', + }, +})); + +type MessageTypeProps = { + messageTypes: Array, + sendMessageToContact: ( + image: string, + text: string, + caption: string, + title: string, + action: string + ) => Promise, +}; + +const Message = (props: MessageTypeProps) => { + const classes = useStyles(); + const messageTypes = props.messageTypes; + const [message, setMessage] = useState({ + id: messageTypes[0] !== undefined ? messageTypes[0].id : -1, + image: '', + text: '', + caption: '', + action: '', + title: '', + }); + const [validation, setValidationState] = useState({ + error: false, + message: '', + }); + const [messageResponse, setMessageResponse] = useState({ + show: false, + response: '', + }); + const validate = () => { + if ( + messageTypes.map((it) => it.id).findIndex((it) => it === message.id) === + -1 + ) { + setValidationState({ error: true, message: 'select message' }); + return false; + } else if (message.text === undefined || message.text.trim().length === 0) { + setValidationState({ error: true, message: 'text cannot be empty' }); + return false; + } else { + setValidationState({ error: false, message: '' }); + } + return true; + }; + const handleChange = (event) => { + setMessage({ ...message, id: event.target.value }); + }; + const talkToChatbot = () => { + if (validate()) { + props + .sendMessageToContact( + message.image.trim() ?? '', + message.text.trim(), + message.caption.trim() ?? '', + message.action.trim() ?? '', + message.title.trim() ?? '' + ) + .then((messageId) => + setMessageResponse({ + show: true, + response: 'Message Id: ' + messageId, + }) + ); + } + }; + + const onImageChange = (event) => { + setMessage({ ...message, image: event.target.value }); + }; + const onTextChange = (event) => { + setMessage({ ...message, text: event.target.value }); + }; + const onCaptionChange = (event) => { + setMessage({ ...message, caption: event.target.value }); + }; + const onActionChange = (event) => { + setMessage({ ...message, action: event.target.value }); + }; + const onTitleChange = (event) => { + setMessage({ ...message, title: event.target.value }); + }; + + const onChatbotClose = () => { + setMessageResponse({ show: false, response: '' }); + }; + return ( + + + Send Message Type + + + + + + + + + + + + + + + + + + {validation.error && ( +
+ {validation.message} +
+ )} + + + + + Response + + {messageResponse.response} + + + + + +
+ ); +}; + +const mapStatetoProps = (state, props) => { + return { + ...props, + messageTypes: state.message.messageTypes, + }; +}; +const mapDispatchToProps = (dispatch) => { + return { + getBots: () => dispatch(getMessageTypeList()), + sendMessageToContact: (image, text, caption, title, action) => + dispatch(sendMessageToContact(image, text, caption, title, action)), + }; +}; + +export default connect(mapStatetoProps, mapDispatchToProps)(Message); diff --git a/js-miniapp-sample/src/pages/tests/chatbot.test.js b/js-miniapp-sample/src/pages/tests/chatbot.test.js deleted file mode 100644 index 6e90d4d28..000000000 --- a/js-miniapp-sample/src/pages/tests/chatbot.test.js +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; - -import userEvent from '@testing-library/user-event'; - -import { - renderWithRedux, - wrapRouter, - screen, - wrapTheme, -} from '../../tests/test-utils'; -import TalkToChatBot from '../chatbot'; - -describe('chatbot', () => { - beforeEach(() => { - renderWithRedux(wrapRouter(wrapTheme())); - }); - test('should load chatbot', () => { - expect(screen.getByText('Chatbot')).toBeInTheDocument(); - expect(screen.getByText('Message')).toBeInTheDocument(); - expect(screen.getByTestId('send-message')).toBeInTheDocument(); - expect(screen.getByPlaceholderText('Select Chatbot')).toBeInTheDocument(); - expect(screen.getByPlaceholderText('Type here...')).toBeInTheDocument(); - expect(screen.queryByTestId('validation-error')).not.toBeInTheDocument(); - }); - - test('should show validation error message when user clicks send button without message', () => { - userEvent.click(screen.getByTestId('send-message')); - const validationBlk = screen.queryByTestId('validation-error'); - expect(validationBlk).toBeInTheDocument(); - expect(validationBlk).toHaveTextContent('enter message to chatbot'); - expect( - screen.queryByTestId('chatbot-response-dialog') - ).not.toBeInTheDocument(); - }); - - test('should show chatbot response', () => { - const messageField = screen.getByPlaceholderText('Type here...'); - userEvent.type(messageField, 'Hello Rajesh'); - userEvent.click(screen.getByTestId('send-message')); - expect(screen.queryByTestId('validation-error')).not.toBeInTheDocument(); - expect(screen.getByTestId('chatbot-response-dialog')).toBeInTheDocument(); - }); -}); diff --git a/js-miniapp-sample/src/pages/tests/message.test.js b/js-miniapp-sample/src/pages/tests/message.test.js new file mode 100644 index 000000000..6fab8ce25 --- /dev/null +++ b/js-miniapp-sample/src/pages/tests/message.test.js @@ -0,0 +1,36 @@ +import React from 'react'; + +import userEvent from '@testing-library/user-event'; + +import { + renderWithRedux, + wrapRouter, + screen, + wrapTheme, +} from '../../tests/test-utils'; +import Message from '../message'; + +describe('chatbot', () => { + beforeEach(() => { + renderWithRedux(wrapRouter(wrapTheme())); + }); + test('should load chatbot', () => { + expect(screen.getByText('Image')).toBeInTheDocument(); + expect(screen.getByText('Text')).toBeInTheDocument(); + expect(screen.getByText('Caption')).toBeInTheDocument(); + expect(screen.getByText('Action')).toBeInTheDocument(); + expect(screen.getByText('Title')).toBeInTheDocument(); + expect(screen.getByTestId('send-message')).toBeInTheDocument(); + expect(screen.queryByTestId('validation-error')).not.toBeInTheDocument(); + }); + + test('should show validation error message when user clicks send button without message', () => { + userEvent.click(screen.getByTestId('send-message')); + const validationBlk = screen.queryByTestId('validation-error'); + expect(validationBlk).toBeInTheDocument(); + expect(validationBlk).toHaveTextContent('text cannot be empty'); + expect( + screen.queryByTestId('chatbot-response-dialog') + ).not.toBeInTheDocument(); + }); +}); diff --git a/js-miniapp-sample/src/routes.js b/js-miniapp-sample/src/routes.js index ad0754510..aeba244ce 100644 --- a/js-miniapp-sample/src/routes.js +++ b/js-miniapp-sample/src/routes.js @@ -18,7 +18,7 @@ import VpnKeyIcon from '@material-ui/icons/VpnKey'; import Ads from './pages/ads'; import AuthToken from './pages/auth-token'; -import TalkToChatBot from './pages/chatbot'; +import TalkToChatBot from './pages/message'; import FetchCredentials from './pages/fetch-credentials'; import FileUploader from './pages/file-upload'; import GifPage from './pages/gifs'; @@ -74,7 +74,7 @@ const appItems = [ }, { icon: , - label: 'Message to Chatbot', + label: 'Message', navLink: '/chatbot', component: TalkToChatBot, }, @@ -127,8 +127,8 @@ const appItems = [ component: GifPage, }, ]; -// $FlowFixMe -const navItems = homeItem.concat( + +const navItems: Object[] = homeItem.concat( appItems.sort((a, b) => a.label.localeCompare(b.label)) ); diff --git a/js-miniapp-sample/src/services/chatbot/actions.js b/js-miniapp-sample/src/services/chatbot/actions.js deleted file mode 100644 index b9a0010e4..000000000 --- a/js-miniapp-sample/src/services/chatbot/actions.js +++ /dev/null @@ -1,24 +0,0 @@ -import { SET_CHATBOTS } from './types'; -import type { SetChatBotsAction } from './types'; - -const getBotsList = (): SetChatBotsAction => { - return { - type: SET_CHATBOTS, - payload: [ - { - id: 1, - name: 'R-Chatbot', - }, - { - id: 2, - name: 'M-Chatbot', - }, - { - id: 3, - name: 'K-Chatbot', - }, - ], - }; -}; - -export { getBotsList }; diff --git a/js-miniapp-sample/src/services/chatbot/reducers.js b/js-miniapp-sample/src/services/chatbot/reducers.js deleted file mode 100644 index f73e871db..000000000 --- a/js-miniapp-sample/src/services/chatbot/reducers.js +++ /dev/null @@ -1,30 +0,0 @@ -import type { ChatBot, ChatBotAction } from './types'; -import { SET_CHATBOTS } from './types'; - -type ChatBotState = { - bots: Array, -}; - -const chatbotState = { - bots: [ - { - id: 1, - name: 'R-Chatbot', - }, - { - id: 2, - name: 'M-Chatbot', - }, - { - id: 3, - name: 'K-Chatbot', - }, - ], -}; - -export default (state: ChatBotState = chatbotState, action: ChatBotAction) => { - if (action.type === SET_CHATBOTS) { - return { ...state, bots: action.payload }; - } - return state; -}; diff --git a/js-miniapp-sample/src/services/chatbot/types.js b/js-miniapp-sample/src/services/chatbot/types.js deleted file mode 100644 index a2a34dc00..000000000 --- a/js-miniapp-sample/src/services/chatbot/types.js +++ /dev/null @@ -1,16 +0,0 @@ -const SET_CHATBOTS = 'GET_CHATBOTS'; - -type ChatBot = { - id: number, - name: string, -}; - -type SetChatBotsAction = { - type: string, - payload: Array, -}; - -type ChatBotAction = SetChatBotsAction; - -export { SET_CHATBOTS }; -export type { ChatBot, SetChatBotsAction, ChatBotAction }; diff --git a/js-miniapp-sample/src/services/message/actions.js b/js-miniapp-sample/src/services/message/actions.js new file mode 100644 index 000000000..daf156ea7 --- /dev/null +++ b/js-miniapp-sample/src/services/message/actions.js @@ -0,0 +1,37 @@ +import { SET_MESSAGE_TYPES } from './types'; +import type { SetMessageTypeAction } from './types'; +import MiniApp from 'js-miniapp-sdk'; +import { MessageToContact } from 'js-miniapp-sdk'; + +const getMessageTypeList = (): SetMessageTypeAction => { + return { + type: SET_MESSAGE_TYPES, + payload: [ + { + id: 1, + name: 'Send a message to a single contact', + }, + ], + }; +}; + +const sendMessageToContact = ( + image: String, + text: String, + caption: String, + title: String, + action: String +): Function => { + return (dispatch) => { + const messageToContact: MessageToContact = { + text: text, + image: image, + caption: caption, + title: title, + action: action, + }; + return MiniApp.chatService.sendMessageToContact(messageToContact); + }; +}; + +export { getMessageTypeList, sendMessageToContact }; diff --git a/js-miniapp-sample/src/services/message/reducers.js b/js-miniapp-sample/src/services/message/reducers.js new file mode 100644 index 000000000..6278cbb61 --- /dev/null +++ b/js-miniapp-sample/src/services/message/reducers.js @@ -0,0 +1,25 @@ +import type { MessageType, SetMessageTypeAction } from './types'; +import { SET_MESSAGE_TYPES } from './types'; + +type MessageTypeState = { + messageTypes: Array, +}; + +const messageTypeState = { + messageTypes: [ + { + id: 1, + name: 'Send a message to a single contact', + }, + ], +}; + +export default ( + state: MessageTypeState, + action: SetMessageTypeAction +) => { + if (action.type === SET_MESSAGE_TYPES) { + return { ...state, messageTypes: action.payload }; + } + return messageTypeState; +}; diff --git a/js-miniapp-sample/src/services/message/types.js b/js-miniapp-sample/src/services/message/types.js new file mode 100644 index 000000000..cb2c881f1 --- /dev/null +++ b/js-miniapp-sample/src/services/message/types.js @@ -0,0 +1,14 @@ +const SET_MESSAGE_TYPES = 'GET_MESSAGE_TYPE'; + +type MessageType = { + id: number, + name: string, +}; + +type SetMessageTypeAction = { + type: string, + payload: Array, +}; + +export { SET_MESSAGE_TYPES }; +export type { MessageType, SetMessageTypeAction }; diff --git a/js-miniapp-sample/src/services/reducers.js b/js-miniapp-sample/src/services/reducers.js index 7fa94cbd3..dd2d04099 100644 --- a/js-miniapp-sample/src/services/reducers.js +++ b/js-miniapp-sample/src/services/reducers.js @@ -1,13 +1,13 @@ import { combineReducers } from 'redux'; -import BotReducer from './chatbot/reducers'; +import MessageReducer from './message/reducers'; import HomeStateReducer from './home/reducers'; import { grantedPermissionsReducer } from './permissions/reducers'; import userReducer from './user/reducers'; import { UUIDReducer } from './uuid/reducers'; export default combineReducers({ - chatbot: BotReducer, + message: MessageReducer, home: HomeStateReducer, permissions: grantedPermissionsReducer, user: userReducer,