diff --git a/packages/server/src/Interface.ts b/packages/server/src/Interface.ts
index 1eafcae68ee..9473638f426 100644
--- a/packages/server/src/Interface.ts
+++ b/packages/server/src/Interface.ts
@@ -13,6 +13,7 @@ export interface IChatFlow {
deployed: boolean
updatedDate: Date
createdDate: Date
+ chatbotConfig?: string
}
export interface IChatMessage {
diff --git a/packages/server/src/entity/ChatFlow.ts b/packages/server/src/entity/ChatFlow.ts
index d9b12929412..910272ad6c6 100644
--- a/packages/server/src/entity/ChatFlow.ts
+++ b/packages/server/src/entity/ChatFlow.ts
@@ -19,6 +19,9 @@ export class ChatFlow implements IChatFlow {
@Column()
deployed: boolean
+ @Column({ nullable: true })
+ chatbotConfig?: string
+
@CreateDateColumn()
createdDate: Date
diff --git a/packages/ui/craco.config.js b/packages/ui/craco.config.js
new file mode 100644
index 00000000000..142305e01b5
--- /dev/null
+++ b/packages/ui/craco.config.js
@@ -0,0 +1,16 @@
+module.exports = {
+ webpack: {
+ configure: {
+ module: {
+ rules: [
+ {
+ test: /\.m?js$/,
+ resolve: {
+ fullySpecified: false
+ }
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 258b54716e4..1e55f1c8a6f 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -16,6 +16,8 @@
"@mui/x-data-grid": "^6.8.0",
"@tabler/icons": "^1.39.1",
"clsx": "^1.1.1",
+ "flowise-embed": "*",
+ "flowise-embed-react": "*",
"formik": "^2.2.6",
"framer-motion": "^4.1.13",
"history": "^5.0.0",
@@ -27,6 +29,7 @@
"prop-types": "^15.7.2",
"react": "^18.2.0",
"react-code-blocks": "^0.0.9-0",
+ "react-color": "^2.19.3",
"react-datepicker": "^4.8.0",
"react-device-detect": "^1.17.0",
"react-dom": "^18.2.0",
@@ -47,11 +50,11 @@
"yup": "^0.32.9"
},
"scripts": {
- "start": "react-scripts start",
- "dev": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
- "eject": "react-scripts eject"
+ "start": "craco start",
+ "dev": "craco start",
+ "build": "craco build",
+ "test": "craco test",
+ "eject": "craco eject"
},
"babel": {
"presets": [
@@ -72,6 +75,7 @@
},
"devDependencies": {
"@babel/eslint-parser": "^7.15.8",
+ "@craco/craco": "^7.1.0",
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^12.8.3",
diff --git a/packages/ui/src/assets/images/sharing.png b/packages/ui/src/assets/images/sharing.png
new file mode 100644
index 00000000000..1e538f2efd2
Binary files /dev/null and b/packages/ui/src/assets/images/sharing.png differ
diff --git a/packages/ui/src/routes/ChatbotRoutes.js b/packages/ui/src/routes/ChatbotRoutes.js
new file mode 100644
index 00000000000..25d298d6854
--- /dev/null
+++ b/packages/ui/src/routes/ChatbotRoutes.js
@@ -0,0 +1,23 @@
+import { lazy } from 'react'
+
+// project imports
+import Loadable from 'ui-component/loading/Loadable'
+import MinimalLayout from 'layout/MinimalLayout'
+
+// canvas routing
+const ChatbotFull = Loadable(lazy(() => import('views/chatbot')))
+
+// ==============================|| CANVAS ROUTING ||============================== //
+
+const ChatbotRoutes = {
+ path: '/',
+ element: ,
+ children: [
+ {
+ path: '/chatbot/:id',
+ element:
+ }
+ ]
+}
+
+export default ChatbotRoutes
diff --git a/packages/ui/src/routes/index.js b/packages/ui/src/routes/index.js
index 15fe4dcab63..ff8c19200ed 100644
--- a/packages/ui/src/routes/index.js
+++ b/packages/ui/src/routes/index.js
@@ -3,10 +3,11 @@ import { useRoutes } from 'react-router-dom'
// routes
import MainRoutes from './MainRoutes'
import CanvasRoutes from './CanvasRoutes'
+import ChatbotRoutes from './ChatbotRoutes'
import config from 'config'
// ==============================|| ROUTING RENDER ||============================== //
export default function ThemeRoutes() {
- return useRoutes([MainRoutes, CanvasRoutes], config.basename)
+ return useRoutes([MainRoutes, CanvasRoutes, ChatbotRoutes], config.basename)
}
diff --git a/packages/ui/src/views/canvas/CanvasHeader.js b/packages/ui/src/views/canvas/CanvasHeader.js
index 1f4a1f93bc4..521aa9d31a9 100644
--- a/packages/ui/src/views/canvas/CanvasHeader.js
+++ b/packages/ui/src/views/canvas/CanvasHeader.js
@@ -13,7 +13,7 @@ import { IconSettings, IconChevronLeft, IconDeviceFloppy, IconPencil, IconCheck,
// project imports
import Settings from 'views/settings'
import SaveChatflowDialog from 'ui-component/dialog/SaveChatflowDialog'
-import APICodeDialog from 'ui-component/dialog/APICodeDialog'
+import APICodeDialog from 'views/chatflows/APICodeDialog'
// API
import chatflowsApi from 'api/chatflows'
@@ -107,7 +107,8 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
title: 'Embed in website or use as API',
chatflowid: chatflow.id,
chatflowApiKeyId: chatflow.apikeyid,
- isFormDataRequired
+ isFormDataRequired,
+ chatbotConfig: chatflow.chatbotConfig
})
setAPIDialogOpen(true)
}
diff --git a/packages/ui/src/views/chatbot/index.js b/packages/ui/src/views/chatbot/index.js
new file mode 100644
index 00000000000..b33bec2c505
--- /dev/null
+++ b/packages/ui/src/views/chatbot/index.js
@@ -0,0 +1,59 @@
+import { useEffect, useState } from 'react'
+import { baseURL } from 'store/constant'
+import axios from 'axios'
+import { FullPageChat } from 'flowise-embed-react'
+
+// ==============================|| Chatbot ||============================== //
+
+const fetchChatflow = async ({ chatflowId }) => {
+ const username = localStorage.getItem('username')
+ const password = localStorage.getItem('password')
+
+ let chatflow = await axios
+ .get(`${baseURL}/api/v1/chatflows/${chatflowId}`, { auth: username && password ? { username, password } : undefined })
+ .then(async function (response) {
+ return response.data
+ })
+ .catch(function (error) {
+ console.error(error)
+ })
+ return chatflow
+}
+
+const ChatbotFull = () => {
+ const URLpath = document.location.pathname.toString().split('/')
+ const chatflowId = URLpath[URLpath.length - 1] === 'chatbot' ? '' : URLpath[URLpath.length - 1]
+
+ const [chatflow, setChatflow] = useState(null)
+ const [chatbotTheme, setChatbotTheme] = useState({})
+
+ useEffect(() => {
+ ;(async () => {
+ const fetchData = async () => {
+ let response = await fetchChatflow({ chatflowId })
+ setChatflow(response)
+ if (response.chatbotConfig) {
+ try {
+ setChatbotTheme(JSON.parse(response.chatbotConfig))
+ } catch (e) {
+ console.error(e)
+ setChatbotTheme({})
+ }
+ }
+ }
+ fetchData()
+ })()
+ }, [chatflowId])
+
+ return (
+ <>
+ {!chatflow || chatflow.apikeyid ? (
+
Invalid Chatbot
+ ) : (
+
+ )}
+ >
+ )
+}
+
+export default ChatbotFull
diff --git a/packages/ui/src/ui-component/dialog/APICodeDialog.js b/packages/ui/src/views/chatflows/APICodeDialog.js
similarity index 73%
rename from packages/ui/src/ui-component/dialog/APICodeDialog.js
rename to packages/ui/src/views/chatflows/APICodeDialog.js
index e64f4bf8667..fea49909e2e 100644
--- a/packages/ui/src/ui-component/dialog/APICodeDialog.js
+++ b/packages/ui/src/views/chatflows/APICodeDialog.js
@@ -9,6 +9,8 @@ import { CopyBlock, atomOneDark } from 'react-code-blocks'
// Project import
import { Dropdown } from 'ui-component/dropdown/Dropdown'
+import ShareChatbot from './ShareChatbot'
+import EmbedChat from './EmbedChat'
// Const
import { baseURL } from 'store/constant'
@@ -19,6 +21,7 @@ import pythonSVG from 'assets/images/python.svg'
import javascriptSVG from 'assets/images/javascript.svg'
import cURLSVG from 'assets/images/cURL.svg'
import EmbedSVG from 'assets/images/embed.svg'
+import ShareChatbotSVG from 'assets/images/sharing.png'
// API
import apiKeyApi from 'api/apikey'
@@ -119,77 +122,19 @@ const getConfigExamplesForCurl = (configData, bodyType) => {
return finalStr
}
-const embedCode = (chatflowid) => {
- return ``
-}
-
-const embedCodeCustomization = (chatflowid) => {
- return ``
-}
-
const APICodeDialog = ({ show, dialogProps, onCancel }) => {
const portalElement = document.getElementById('portal')
const navigate = useNavigate()
const dispatch = useDispatch()
- const codes = ['Embed', 'Python', 'JavaScript', 'cURL']
+
+ const codes = ['Embed', 'Python', 'JavaScript', 'cURL', 'Share Chatbot']
const [value, setValue] = useState(0)
const [keyOptions, setKeyOptions] = useState([])
const [apiKeys, setAPIKeys] = useState([])
const [chatflowApiKeyId, setChatflowApiKeyId] = useState('')
const [selectedApiKey, setSelectedApiKey] = useState({})
const [checkboxVal, setCheckbox] = useState(false)
- const [embedChatCheckboxVal, setEmbedChatCheckbox] = useState(false)
+ const [chatbotConfig, setChatbotConfig] = useState(null)
const getAllAPIKeysApi = useApi(apiKeyApi.getAllAPIKeys)
const updateChatflowApi = useApi(chatflowsApi.updateChatflow)
@@ -203,10 +148,6 @@ const APICodeDialog = ({ show, dialogProps, onCancel }) => {
}
}
- const onCheckBoxEmbedChatChanged = (newVal) => {
- setEmbedChatCheckbox(newVal)
- }
-
const onApiKeySelected = (keyValue) => {
if (keyValue === 'addnewkey') {
navigate('/apikey')
@@ -265,8 +206,6 @@ query({"question": "Hey, how are you?"}).then((response) => {
return `curl ${baseURL}/api/v1/prediction/${dialogProps.chatflowid} \\
-X POST \\
-d '{"question": "Hey, how are you?"}'`
- } else if (codeLang === 'Embed') {
- return embedCode(dialogProps.chatflowid)
}
return ''
}
@@ -309,8 +248,6 @@ query({"question": "Hey, how are you?"}).then((response) => {
-X POST \\
-d '{"question": "Hey, how are you?"}' \\
-H "Authorization: Bearer ${selectedApiKey?.apiKey}"`
- } else if (codeLang === 'Embed') {
- return embedCode(dialogProps.chatflowid)
}
return ''
}
@@ -318,7 +255,7 @@ query({"question": "Hey, how are you?"}).then((response) => {
const getLang = (codeLang) => {
if (codeLang === 'Python') {
return 'python'
- } else if (codeLang === 'JavaScript' || codeLang === 'Embed') {
+ } else if (codeLang === 'JavaScript') {
return 'javascript'
} else if (codeLang === 'cURL') {
return 'bash'
@@ -335,6 +272,8 @@ query({"question": "Hey, how are you?"}).then((response) => {
return EmbedSVG
} else if (codeLang === 'cURL') {
return cURLSVG
+ } else if (codeLang === 'Share Chatbot') {
+ return ShareChatbotSVG
}
return pythonSVG
}
@@ -552,6 +491,12 @@ query({
setChatflowApiKeyId(dialogProps.chatflowApiKeyId)
setSelectedApiKey(getAllAPIKeysApi.data.find((key) => key.id === dialogProps.chatflowApiKeyId))
}
+
+ if (dialogProps.chatbotConfig) {
+ setChatbotConfig(JSON.parse(dialogProps.chatbotConfig))
+ } else {
+ setChatbotConfig(null)
+ }
}
}, [dialogProps, getAllAPIKeysApi.data])
@@ -593,92 +538,71 @@ query({
))}
- {value !== 0 && (
-
- onApiKeySelected(newValue)}
- value={dialogProps.chatflowApiKeyId ?? chatflowApiKeyId ?? 'Choose an API key'}
- />
-
- )}
+
+ onApiKeySelected(newValue)}
+ value={dialogProps.chatflowApiKeyId ?? chatflowApiKeyId ?? 'Choose an API key'}
+ />
+
{codes.map((codeLang, index) => (
- {value === 0 && (
+ {(codeLang === 'Embed' || codeLang === 'Share Chatbot') && chatflowApiKeyId && (
<>
-
- Paste this anywhere in the {``}
tag of your html file.
-
- You can also specify a
-
- version
-
- : {`https://cdn.jsdelivr.net/npm/flowise-embed@/dist/web.js`}
-
-
-
+ You cannot use API key while embedding/sharing chatbot.
+
+ Please select "No Authorization" from the dropdown at the top right corner.
+
>
)}
-
- {value !== 0 && }
- {value !== 0 && checkboxVal && getConfigApi.data && getConfigApi.data.length > 0 && (
+ {codeLang === 'Embed' && !chatflowApiKeyId && }
+ {codeLang !== 'Embed' && codeLang !== 'Share Chatbot' && (
<>
-
+
+ {checkboxVal && getConfigApi.data && getConfigApi.data.length > 0 && (
+ <>
+
+
+ >
+ )}
+ {getIsChatflowStreamingApi.data?.isStreaming && (
+
+ Read
+
+ here
+
+ on how to stream response back to application
+
+ )}
>
)}
- {value === 0 && (
-
- )}
- {value === 0 && embedChatCheckboxVal && (
-
- )}
- {value !== 0 && getIsChatflowStreamingApi.data?.isStreaming && (
-
- Read
-
- here
-
- on how to stream response back to application
-
+ {codeLang === 'Share Chatbot' && !chatflowApiKeyId && (
+
)}
))}
diff --git a/packages/ui/src/views/chatflows/EmbedChat.js b/packages/ui/src/views/chatflows/EmbedChat.js
new file mode 100644
index 00000000000..c6385efbad9
--- /dev/null
+++ b/packages/ui/src/views/chatflows/EmbedChat.js
@@ -0,0 +1,324 @@
+import { useState } from 'react'
+import PropTypes from 'prop-types'
+
+import { Tabs, Tab, Box } from '@mui/material'
+import { CopyBlock, atomOneDark } from 'react-code-blocks'
+
+// Project import
+import { CheckboxInput } from 'ui-component/checkbox/Checkbox'
+
+// Const
+import { baseURL } from 'store/constant'
+
+function TabPanel(props) {
+ const { children, value, index, ...other } = props
+ return (
+
+ {value === index && {children}}
+
+ )
+}
+
+TabPanel.propTypes = {
+ children: PropTypes.node,
+ index: PropTypes.number.isRequired,
+ value: PropTypes.number.isRequired
+}
+
+function a11yProps(index) {
+ return {
+ id: `attachment-tab-${index}`,
+ 'aria-controls': `attachment-tabpanel-${index}`
+ }
+}
+
+const embedPopupHtmlCode = (chatflowid) => {
+ return ``
+}
+
+const embedPopupReactCode = (chatflowid) => {
+ return `import { BubbleChat } from 'flowise-embed-react'
+
+const App = () => {
+ return (
+
+ );
+};`
+}
+
+const embedFullpageHtmlCode = (chatflowid) => {
+ return `
+`
+}
+
+const embedFullpageReactCode = (chatflowid) => {
+ return `import { FullPageChat } from "flowise-embed-react"
+
+const App = () => {
+ return (
+
+ );
+};`
+}
+
+const buttonConfig = (isReact = false) => {
+ return isReact
+ ? `button: {
+ backgroundColor: "#3B81F6",
+ right: 20,
+ bottom: 20,
+ size: "medium",
+ iconColor: "white",
+ customIconSrc: "https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg",
+ }`
+ : `button: {
+ backgroundColor: "#3B81F6",
+ right: 20,
+ bottom: 20,
+ size: "medium",
+ iconColor: "white",
+ customIconSrc: "https://raw.githubusercontent.com/walkxcode/dashboard-icons/main/svg/google-messages.svg",
+ }`
+}
+
+const chatwindowConfig = (isReact = false) => {
+ return isReact
+ ? `chatWindow: {
+ welcomeMessage: "Hello! This is custom welcome message",
+ backgroundColor: "#ffffff",
+ height: 700,
+ width: 400,
+ fontSize: 16,
+ poweredByTextColor: "#303235",
+ botMessage: {
+ backgroundColor: "#f7f8ff",
+ textColor: "#303235",
+ showAvatar: true,
+ avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png",
+ },
+ userMessage: {
+ backgroundColor: "#3B81F6",
+ textColor: "#ffffff",
+ showAvatar: true,
+ avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png",
+ },
+ textInput: {
+ placeholder: "Type your question",
+ backgroundColor: "#ffffff",
+ textColor: "#303235",
+ sendButtonColor: "#3B81F6",
+ }
+ }`
+ : `chatWindow: {
+ welcomeMessage: "Hello! This is custom welcome message",
+ backgroundColor: "#ffffff",
+ height: 700,
+ width: 400,
+ fontSize: 16,
+ poweredByTextColor: "#303235",
+ botMessage: {
+ backgroundColor: "#f7f8ff",
+ textColor: "#303235",
+ showAvatar: true,
+ avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png",
+ },
+ userMessage: {
+ backgroundColor: "#3B81F6",
+ textColor: "#ffffff",
+ showAvatar: true,
+ avatarSrc: "https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png",
+ },
+ textInput: {
+ placeholder: "Type your question",
+ backgroundColor: "#ffffff",
+ textColor: "#303235",
+ sendButtonColor: "#3B81F6",
+ }
+ }`
+}
+
+const embedPopupHtmlCodeCustomization = (chatflowid) => {
+ return ``
+}
+
+const embedPopupReactCodeCustomization = (chatflowid) => {
+ return `import { BubbleChat } from 'flowise-embed-react'
+
+const App = () => {
+ return (
+
+ );
+};`
+}
+
+const embedFullpageHtmlCodeCustomization = (chatflowid) => {
+ return `
+`
+}
+
+const embedFullpageReactCodeCustomization = (chatflowid) => {
+ return `import { FullPageChat } from "flowise-embed-react"
+
+const App = () => {
+ return (
+
+ );
+};`
+}
+
+const EmbedChat = ({ chatflowid }) => {
+ const codes = ['Popup Html', 'Fullpage Html', 'Popup React', 'Fullpage React']
+ const [value, setValue] = useState(0)
+ const [embedChatCheckboxVal, setEmbedChatCheckbox] = useState(false)
+
+ const onCheckBoxEmbedChatChanged = (newVal) => {
+ setEmbedChatCheckbox(newVal)
+ }
+
+ const handleChange = (event, newValue) => {
+ setValue(newValue)
+ }
+
+ const getCode = (codeLang) => {
+ switch (codeLang) {
+ case 'Popup Html':
+ return embedPopupHtmlCode(chatflowid)
+ case 'Fullpage Html':
+ return embedFullpageHtmlCode(chatflowid)
+ case 'Popup React':
+ return embedPopupReactCode(chatflowid)
+ case 'Fullpage React':
+ return embedFullpageReactCode(chatflowid)
+ default:
+ return ''
+ }
+ }
+
+ const getCodeCustomization = (codeLang) => {
+ switch (codeLang) {
+ case 'Popup Html':
+ return embedPopupHtmlCodeCustomization(chatflowid)
+ case 'Fullpage Html':
+ return embedFullpageHtmlCodeCustomization(chatflowid)
+ case 'Popup React':
+ return embedPopupReactCodeCustomization(chatflowid)
+ case 'Fullpage React':
+ return embedFullpageReactCodeCustomization(chatflowid)
+ default:
+ return ''
+ }
+ }
+
+ return (
+ <>
+
+
+
+ {codes.map((codeLang, index) => (
+
+ ))}
+
+
+
+
+ {codes.map((codeLang, index) => (
+
+ {(value === 0 || value === 1) && (
+ <>
+
+ Paste this anywhere in the {``}
tag of your html file.
+
+ You can also specify a
+
+ version
+
+ : {`https://cdn.jsdelivr.net/npm/flowise-embed@/dist/web.js`}
+
+
+
+ >
+ )}
+
+
+
+
+ {embedChatCheckboxVal && (
+
+ )}
+
+ ))}
+ >
+ )
+}
+
+EmbedChat.propTypes = {
+ chatflowid: PropTypes.string
+}
+
+export default EmbedChat
diff --git a/packages/ui/src/views/chatflows/ShareChatbot.js b/packages/ui/src/views/chatflows/ShareChatbot.js
new file mode 100644
index 00000000000..dffecf5b7dc
--- /dev/null
+++ b/packages/ui/src/views/chatflows/ShareChatbot.js
@@ -0,0 +1,420 @@
+import PropTypes from 'prop-types'
+import { useState } from 'react'
+import { useDispatch } from 'react-redux'
+import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction } from 'store/actions'
+import { SketchPicker } from 'react-color'
+
+import { Box, Typography, Button, Switch, OutlinedInput, Popover, Stack, IconButton } from '@mui/material'
+import { useTheme } from '@mui/material/styles'
+
+// Project import
+import { StyledButton } from 'ui-component/button/StyledButton'
+
+// Icons
+import { IconX, IconCopy, IconArrowUpRightCircle } from '@tabler/icons'
+
+// API
+import chatflowsApi from 'api/chatflows'
+
+// utils
+import useNotifier from 'utils/useNotifier'
+
+// Const
+import { baseURL } from 'store/constant'
+
+const defaultConfig = {
+ backgroundColor: '#ffffff',
+ fontSize: 16,
+ poweredByTextColor: '#303235',
+ botMessage: {
+ backgroundColor: '#f7f8ff',
+ textColor: '#303235'
+ },
+ userMessage: {
+ backgroundColor: '#3B81F6',
+ textColor: '#ffffff'
+ },
+ textInput: {
+ backgroundColor: '#ffffff',
+ textColor: '#303235',
+ sendButtonColor: '#3B81F6'
+ }
+}
+
+const ShareChatbot = ({ chatflowid, chatbotConfig }) => {
+ const dispatch = useDispatch()
+ const theme = useTheme()
+
+ useNotifier()
+
+ const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
+ const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
+
+ const [welcomeMessage, setWelcomeMessage] = useState(chatbotConfig?.welcomeMessage ?? '')
+ const [backgroundColor, setBackgroundColor] = useState(chatbotConfig?.backgroundColor ?? defaultConfig.backgroundColor)
+ const [fontSize, setFontSize] = useState(chatbotConfig?.fontSize ?? defaultConfig.fontSize)
+ const [poweredByTextColor, setPoweredByTextColor] = useState(chatbotConfig?.poweredByTextColor ?? defaultConfig.poweredByTextColor)
+
+ const [botMessageBackgroundColor, setBotMessageBackgroundColor] = useState(
+ chatbotConfig?.botMessage?.backgroundColor ?? defaultConfig.botMessage.backgroundColor
+ )
+ const [botMessageTextColor, setBotMessageTextColor] = useState(
+ chatbotConfig?.botMessage?.textColor ?? defaultConfig.botMessage.textColor
+ )
+ const [botMessageAvatarSrc, setBotMessageAvatarSrc] = useState(chatbotConfig?.botMessage?.avatarSrc ?? '')
+ const [botMessageShowAvatar, setBotMessageShowAvatar] = useState(chatbotConfig?.botMessage?.showAvatar ?? false)
+
+ const [userMessageBackgroundColor, setUserMessageBackgroundColor] = useState(
+ chatbotConfig?.userMessage?.backgroundColor ?? defaultConfig.userMessage.backgroundColor
+ )
+ const [userMessageTextColor, setUserMessageTextColor] = useState(
+ chatbotConfig?.userMessage?.textColor ?? defaultConfig.userMessage.textColor
+ )
+ const [userMessageAvatarSrc, setUserMessageAvatarSrc] = useState(chatbotConfig?.userMessage?.avatarSrc ?? '')
+ const [userMessageShowAvatar, setUserMessageShowAvatar] = useState(chatbotConfig?.userMessage?.showAvatar ?? false)
+
+ const [textInputBackgroundColor, setTextInputBackgroundColor] = useState(
+ chatbotConfig?.textInput?.backgroundColor ?? defaultConfig.textInput.backgroundColor
+ )
+ const [textInputTextColor, setTextInputTextColor] = useState(chatbotConfig?.textInput?.textColor ?? defaultConfig.textInput.textColor)
+ const [textInputPlaceholder, setTextInputPlaceholder] = useState(chatbotConfig?.textInput?.placeholder ?? '')
+ const [textInputSendButtonColor, setTextInputSendButtonColor] = useState(
+ chatbotConfig?.textInput?.sendButtonColor ?? defaultConfig.textInput.sendButtonColor
+ )
+
+ const [colorAnchorEl, setColorAnchorEl] = useState(null)
+ const [selectedColorConfig, setSelectedColorConfig] = useState('')
+ const [sketchPickerColor, setSketchPickerColor] = useState('')
+ const openColorPopOver = Boolean(colorAnchorEl)
+
+ const [copyAnchorEl, setCopyAnchorEl] = useState(null)
+ const openCopyPopOver = Boolean(copyAnchorEl)
+
+ const formatObj = () => {
+ const obj = {
+ botMessage: {
+ showAvatar: false
+ },
+ userMessage: {
+ showAvatar: false
+ },
+ textInput: {}
+ }
+ if (welcomeMessage) obj.welcomeMessage = welcomeMessage
+ if (backgroundColor) obj.backgroundColor = backgroundColor
+ if (fontSize) obj.fontSize = fontSize
+ if (poweredByTextColor) obj.poweredByTextColor = poweredByTextColor
+
+ if (botMessageBackgroundColor) obj.botMessage.backgroundColor = botMessageBackgroundColor
+ if (botMessageTextColor) obj.botMessage.textColor = botMessageTextColor
+ if (botMessageAvatarSrc) obj.botMessage.avatarSrc = botMessageAvatarSrc
+ if (botMessageShowAvatar) obj.botMessage.showAvatar = botMessageShowAvatar
+
+ if (userMessageBackgroundColor) obj.userMessage.backgroundColor = userMessageBackgroundColor
+ if (userMessageTextColor) obj.userMessage.textColor = userMessageTextColor
+ if (userMessageAvatarSrc) obj.userMessage.avatarSrc = userMessageAvatarSrc
+ if (userMessageShowAvatar) obj.userMessage.showAvatar = userMessageShowAvatar
+
+ if (textInputBackgroundColor) obj.textInput.backgroundColor = textInputBackgroundColor
+ if (textInputTextColor) obj.textInput.textColor = textInputTextColor
+ if (textInputPlaceholder) obj.textInput.placeholder = textInputPlaceholder
+ if (textInputSendButtonColor) obj.textInput.sendButtonColor = textInputSendButtonColor
+
+ return obj
+ }
+
+ const onSave = async () => {
+ try {
+ const saveResp = await chatflowsApi.updateChatflow(chatflowid, {
+ chatbotConfig: JSON.stringify(formatObj())
+ })
+ if (saveResp.data) {
+ enqueueSnackbar({
+ message: 'Chatbot Configuration Saved',
+ options: {
+ key: new Date().getTime() + Math.random(),
+ variant: 'success',
+ action: (key) => (
+
+ )
+ }
+ })
+ }
+ } catch (error) {
+ console.error(error)
+ const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}`
+ enqueueSnackbar({
+ message: `Failed to save Chatbot Configuration: ${errorData}`,
+ options: {
+ key: new Date().getTime() + Math.random(),
+ variant: 'error',
+ persist: true,
+ action: (key) => (
+
+ )
+ }
+ })
+ }
+ }
+
+ const handleClosePopOver = () => {
+ setColorAnchorEl(null)
+ }
+
+ const handleCloseCopyPopOver = () => {
+ setCopyAnchorEl(null)
+ }
+
+ const onColorSelected = (hexColor) => {
+ switch (selectedColorConfig) {
+ case 'backgroundColor':
+ setBackgroundColor(hexColor)
+ break
+ case 'poweredByTextColor':
+ setPoweredByTextColor(hexColor)
+ break
+ case 'botMessageBackgroundColor':
+ setBotMessageBackgroundColor(hexColor)
+ break
+ case 'botMessageTextColor':
+ setBotMessageTextColor(hexColor)
+ break
+ case 'userMessageBackgroundColor':
+ setUserMessageBackgroundColor(hexColor)
+ break
+ case 'userMessageTextColor':
+ setUserMessageTextColor(hexColor)
+ break
+ case 'textInputBackgroundColor':
+ setTextInputBackgroundColor(hexColor)
+ break
+ case 'textInputTextColor':
+ setTextInputTextColor(hexColor)
+ break
+ case 'textInputSendButtonColor':
+ setTextInputSendButtonColor(hexColor)
+ break
+ }
+ setSketchPickerColor(hexColor)
+ }
+
+ const onTextChanged = (value, fieldName) => {
+ switch (fieldName) {
+ case 'welcomeMessage':
+ setWelcomeMessage(value)
+ break
+ case 'fontSize':
+ setFontSize(value)
+ break
+ case 'botMessageAvatarSrc':
+ setBotMessageAvatarSrc(value)
+ break
+ case 'userMessageAvatarSrc':
+ setUserMessageAvatarSrc(value)
+ break
+ case 'textInputPlaceholder':
+ setTextInputPlaceholder(value)
+ break
+ }
+ }
+
+ const onBooleanChanged = (value, fieldName) => {
+ switch (fieldName) {
+ case 'botMessageShowAvatar':
+ setBotMessageShowAvatar(value)
+ break
+ case 'userMessageShowAvatar':
+ setUserMessageShowAvatar(value)
+ break
+ }
+ }
+
+ const colorField = (color, fieldName, fieldLabel) => {
+ return (
+
+
+ {fieldLabel}
+ {
+ setSelectedColorConfig(fieldName)
+ setSketchPickerColor(color ?? '#ffffff')
+ setColorAnchorEl(event.currentTarget)
+ }}
+ >
+
+
+ )
+ }
+
+ const booleanField = (value, fieldName, fieldLabel) => {
+ return (
+
+
+ {fieldLabel}
+ {
+ onBooleanChanged(event.target.checked, fieldName)
+ }}
+ />
+
+
+ )
+ }
+
+ const textField = (message, fieldName, fieldLabel, fieldType = 'string', placeholder = '') => {
+ return (
+
+
+ {fieldLabel}
+ {
+ onTextChanged(e.target.value, fieldName)
+ }}
+ />
+
+
+ )
+ }
+
+ return (
+ <>
+
+
+ {`${baseURL}/chatbot/${chatflowid}`}
+
+ {
+ navigator.clipboard.writeText(`${baseURL}/chatbot/${chatflowid}`)
+ setCopyAnchorEl(event.currentTarget)
+ setTimeout(() => {
+ handleCloseCopyPopOver()
+ }, 1500)
+ }}
+ >
+
+
+ window.open(`${baseURL}/chatbot/${chatflowid}`, '_blank')}>
+
+
+
+ {textField(welcomeMessage, 'welcomeMessage', 'Welcome Message', 'string', 'Hello! This is custom welcome message')}
+ {colorField(backgroundColor, 'backgroundColor', 'Background Color')}
+ {textField(fontSize, 'fontSize', 'Font Size', 'number')}
+ {colorField(poweredByTextColor, 'poweredByTextColor', 'PoweredBy TextColor')}
+
+ {/*BOT Message*/}
+
+ Bot Message
+
+ {colorField(botMessageBackgroundColor, 'botMessageBackgroundColor', 'Background Color')}
+ {colorField(botMessageTextColor, 'botMessageTextColor', 'Text Color')}
+ {textField(
+ botMessageAvatarSrc,
+ 'botMessageAvatarSrc',
+ 'Avatar Link',
+ 'string',
+ `https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png`
+ )}
+ {booleanField(botMessageShowAvatar, 'botMessageShowAvatar', 'Show Avatar')}
+
+ {/*USER Message*/}
+
+ User Message
+
+ {colorField(userMessageBackgroundColor, 'userMessageBackgroundColor', 'Background Color')}
+ {colorField(userMessageTextColor, 'userMessageTextColor', 'Text Color')}
+ {textField(
+ userMessageAvatarSrc,
+ 'userMessageAvatarSrc',
+ 'Avatar Link',
+ 'string',
+ `https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/usericon.png`
+ )}
+ {booleanField(userMessageShowAvatar, 'userMessageShowAvatar', 'Show Avatar')}
+
+ {/*TEXT Input*/}
+
+ Text Input
+
+ {colorField(textInputBackgroundColor, 'textInputBackgroundColor', 'Background Color')}
+ {colorField(textInputTextColor, 'textInputTextColor', 'Text Color')}
+ {textField(textInputPlaceholder, 'textInputPlaceholder', 'TextInput Placeholder', 'string', `Type question..`)}
+ {colorField(textInputSendButtonColor, 'textInputSendButtonColor', 'TextIntput Send Button Color')}
+
+ onSave()}>
+ Save Changes
+
+
+ onColorSelected(color.hex)} />
+
+
+
+ Copied!
+
+
+ >
+ )
+}
+
+ShareChatbot.propTypes = {
+ chatflowid: PropTypes.string,
+ chatbotConfig: PropTypes.object
+}
+
+export default ShareChatbot