From 51425334567e0613aa76ca522b9ec836fc2d0bd3 Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Thu, 6 Jul 2023 12:47:31 +0530 Subject: [PATCH 01/10] chore: remove env file --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4d29575..7d5217e 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ .env.development.local .env.test.local .env.production.local - +.env npm-debug.log* yarn-debug.log* yarn-error.log* From 3e8ef6c6b3e57ff5fe772d3e2b996ae90089d21e Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Thu, 6 Jul 2023 13:56:48 +0530 Subject: [PATCH 02/10] fix: transformer id set --- src/api/api-util-functions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/api-util-functions.ts b/src/api/api-util-functions.ts index 035b166..fba7c3f 100644 --- a/src/api/api-util-functions.ts +++ b/src/api/api-util-functions.ts @@ -164,6 +164,7 @@ export const onCreateBroadcastBotLogic = () => { adapter: process.env.REACT_APP_broadcastAdapterId, transformers: [ { + "id": "774cd134-6657-4688-85f6-6338e2323dde", meta: { type: "broadcast", data: { botId: store?.conversationBot.id }, From 75d1da6d2a88fafe1cff1be6ec0025fd6837c64b Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Thu, 6 Jul 2023 14:57:22 +0530 Subject: [PATCH 03/10] fix: transformer logic updated for broadcast --- src/api/api-util-functions.ts | 21 +++++++++++++++++++++ src/components/addLogicModal/index.tsx | 1 + 2 files changed, 22 insertions(+) diff --git a/src/api/api-util-functions.ts b/src/api/api-util-functions.ts index fba7c3f..9c1b15c 100644 --- a/src/api/api-util-functions.ts +++ b/src/api/api-util-functions.ts @@ -158,7 +158,9 @@ export const onAfterBotSubmit = (extras) => { export const onCreateBroadcastBotLogic = () => { const store: any = useStore.getState(); + console.log({store}) for (const botLogic of store?.conversationLogic) { + console.log({botLogic}) const newBotLogic = { ...botLogic, adapter: process.env.REACT_APP_broadcastAdapterId, @@ -168,9 +170,28 @@ export const onCreateBroadcastBotLogic = () => { meta: { type: "broadcast", data: { botId: store?.conversationBot.id }, + title: store?.conversationLogic?.[0]?.name, + body: store?.conversationLogic?.[0]?.description || store?.state?.description || "", + formID: localStorage.getItem('formID'), + "form": "https://hosted.my.form.here.com/", + "serviceClass": "SurveyService", + "hiddenFields": [ + { + "name": "mobilePhone", + "path": "mobilePhone", + "type": "param", + "config": { + "dataObjName": "user" + } + } + ], + "templateType": "JS_TEMPLATE_LITERALS" }, + }, ], + + }; // eslint-disable-next-line no-loop-func addLogic({ data: newBotLogic }) diff --git a/src/components/addLogicModal/index.tsx b/src/components/addLogicModal/index.tsx index f9e977a..a2c6cdf 100644 --- a/src/components/addLogicModal/index.tsx +++ b/src/components/addLogicModal/index.tsx @@ -104,6 +104,7 @@ const AddLogicModal: FC = ({ if(res?.data?.result?.status==='ERROR'){ toast.error(`${getUploadErrorMsg(res?.data?.result?.errorCode)}`) }else{ + localStorage.setItem("formID",res?.data?.result?.data?.formID) setFormId(res?.data?.result?.data?.formID); toast.success("Succesfully Uploaded"); From 69ed0c0a9fd04556d4b68930cd06278e004f3a63 Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:05:30 +0530 Subject: [PATCH 04/10] feat: segment mapping added --- src/api/api-util-functions.ts | 67 +++++++++++++++++++++-------------- src/api/urls.ts | 2 +- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/api/api-util-functions.ts b/src/api/api-util-functions.ts index 9c1b15c..361eabc 100644 --- a/src/api/api-util-functions.ts +++ b/src/api/api-util-functions.ts @@ -7,9 +7,10 @@ import { addLogic } from "./addLogic"; import { toast } from "react-hot-toast"; import { history } from "../utils/history"; import { updateBot } from "./updateBot"; +import { segmentMappingUrl } from "./urls"; +import { mapToSegment } from "./segment-mapping"; export const onBotCreate = (isTriggerBot = false, isNavigateToEnd = false) => { - const store: any = useStore.getState(); store.startLoading(); @@ -125,7 +126,6 @@ export const afterBroadcastBotLogic = () => { } }; - export const onStartConversation = (bot, isNavigateToEnd = false) => { const store: any = useStore.getState(); startConversation(bot) @@ -151,47 +151,59 @@ export const onStartConversation = (bot, isNavigateToEnd = false) => { export const onAfterBotSubmit = (extras) => { const store: any = useStore.getState(); - store.stopLoading(); - store.onReset(); - history.navigate("/success"); + const mappingData = { + segmentId: parseInt(store?.state?.segmentId, 10), + botId: store.conversationBot.botId, + }; + + mapToSegment(mappingData) + .then((res) => { + store.stopLoading(); + store.onReset(); + history.navigate("/success"); + }) + .catch((err) => { + toast.error(err?.message); + store.stopLoading(); + }); }; export const onCreateBroadcastBotLogic = () => { const store: any = useStore.getState(); - console.log({store}) + console.log({ store }); for (const botLogic of store?.conversationLogic) { - console.log({botLogic}) + console.log({ botLogic }); const newBotLogic = { ...botLogic, adapter: process.env.REACT_APP_broadcastAdapterId, transformers: [ { - "id": "774cd134-6657-4688-85f6-6338e2323dde", + id: "774cd134-6657-4688-85f6-6338e2323dde", meta: { type: "broadcast", data: { botId: store?.conversationBot.id }, title: store?.conversationLogic?.[0]?.name, - body: store?.conversationLogic?.[0]?.description || store?.state?.description || "", - formID: localStorage.getItem('formID'), - "form": "https://hosted.my.form.here.com/", - "serviceClass": "SurveyService", - "hiddenFields": [ - { - "name": "mobilePhone", - "path": "mobilePhone", - "type": "param", - "config": { - "dataObjName": "user" - } - } + body: + store?.conversationLogic?.[0]?.description || + store?.state?.description || + "", + formID: localStorage.getItem("formID"), + form: "https://hosted.my.form.here.com/", + serviceClass: "SurveyService", + hiddenFields: [ + { + name: "mobilePhone", + path: "mobilePhone", + type: "param", + config: { + dataObjName: "user", + }, + }, ], - "templateType": "JS_TEMPLATE_LITERALS" + templateType: "JS_TEMPLATE_LITERALS", }, - }, ], - - }; // eslint-disable-next-line no-loop-func addLogic({ data: newBotLogic }) @@ -205,7 +217,10 @@ export const onCreateBroadcastBotLogic = () => { setTimeout(() => { const _store: any = useStore.getState(); - if (_store?.conversationLogic.length <= _store?.broadcastBotLogics.length) { + if ( + _store?.conversationLogic.length <= + _store?.broadcastBotLogics.length + ) { _store?.setConversationLogic(_store?.broadcastBotLogics); setTimeout(() => { onBotCreate(true, true); diff --git a/src/api/urls.ts b/src/api/urls.ts index 75e2039..dd0125d 100644 --- a/src/api/urls.ts +++ b/src/api/urls.ts @@ -10,7 +10,7 @@ export const createBotUrl = `${process.env.REACT_APP_UCI_BASE_URL}/admin/bot`; export const getUpdateBotUrl = (id:string) =>`${process.env.REACT_APP_UCI_BASE_URL}/admin/bot/${id}` -export const segmentMappingUrl = `${process.env.REACT_APP_UCI_BASE_URL}/segment-bot-mapping`; +export const segmentMappingUrl = `${process.env.REACT_APP_user_segment_url}/segment-bot-mapping`; export const createSegmentUrl = `${process.env.REACT_APP_UCI_BASE_URL}/admin/user-segment`; From 9fae4fcf569b3221c9ae207970046a3ad101bb23 Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:07:28 +0530 Subject: [PATCH 05/10] chore: code clean --- src/api/api-util-functions.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/api-util-functions.ts b/src/api/api-util-functions.ts index 361eabc..6f6a13b 100644 --- a/src/api/api-util-functions.ts +++ b/src/api/api-util-functions.ts @@ -7,7 +7,6 @@ import { addLogic } from "./addLogic"; import { toast } from "react-hot-toast"; import { history } from "../utils/history"; import { updateBot } from "./updateBot"; -import { segmentMappingUrl } from "./urls"; import { mapToSegment } from "./segment-mapping"; export const onBotCreate = (isTriggerBot = false, isNavigateToEnd = false) => { From 8dddc1cdf00d6ecc73056f8afc02a1ed53833d69 Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:43:43 +0530 Subject: [PATCH 06/10] fix: transformer meta updated --- src/components/addLogicModal/index.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/components/addLogicModal/index.tsx b/src/components/addLogicModal/index.tsx index a2c6cdf..770af52 100644 --- a/src/components/addLogicModal/index.tsx +++ b/src/components/addLogicModal/index.tsx @@ -61,6 +61,19 @@ const AddLogicModal: FC = ({ formID: formId, title: modalState.name, body: modalState.description, + serviceClass: "SurveyService", + hiddenFields: [ + { + name: "mobilePhone", + path: "mobilePhone", + type: "param", + config: { + dataObjName: "user", + }, + }, + ], + templateType: "JS_TEMPLATE_LITERALS", + }, }, ], From 7f0d02dd8ea805a30a96f3f5e13d71a6ab24b42a Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Wed, 26 Jul 2023 11:56:44 +0530 Subject: [PATCH 07/10] feat: multiple media upload --- src/components/addLogicModal/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/addLogicModal/index.tsx b/src/components/addLogicModal/index.tsx index b2906dc..5c14b8a 100644 --- a/src/components/addLogicModal/index.tsx +++ b/src/components/addLogicModal/index.tsx @@ -213,10 +213,11 @@ const AddLogicModal: FC = ({ From 8c9025eeb626c1538c4817d223014ae016c27e09 Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:06:41 +0530 Subject: [PATCH 08/10] Fix bot mapping (#46) * fix: bot segment mapping * chore: meta update for conversation bot * chore: code clean * feat: edit bot implemented * feat: orderby for search * feat: all media upload supported --- src/api/api-util-functions.ts | 76 ++++--- src/api/getBots.ts | 15 +- src/api/updateBot.ts | 3 +- src/components/addLogicModal/index.tsx | 5 +- src/components/conversationFlow/index.tsx | 1 + src/components/conversationSetup/index.tsx | 127 +++++++----- src/components/table/index.tsx | 17 +- src/index.css | 18 ++ src/pages/add/index.jsx | 218 +++++++++++++-------- src/pages/dashboard/index.tsx | 121 ++++++++++-- src/store/index.ts | 3 + 11 files changed, 396 insertions(+), 208 deletions(-) diff --git a/src/api/api-util-functions.ts b/src/api/api-util-functions.ts index 02fa81f..be62960 100644 --- a/src/api/api-util-functions.ts +++ b/src/api/api-util-functions.ts @@ -9,6 +9,7 @@ import { history } from "../utils/history"; import { updateBot } from "./updateBot"; import { mapToSegment } from "./segment-mapping"; + export const onBotCreate = () => { const store: any = useStore.getState(); store.startLoading(); @@ -49,25 +50,27 @@ export const onBotCreate = () => { text: store?.state?.startingMessage, botId: res.data.result.id, }); - onMappingBotToSegment({ - queryParams: { - text: reqObj.startingMessage, - botId: res.data.result.id, - } - }).then((res) => { - if(store?.isBroadcastBot){ - onSegmentCreate() - } - else { - store?.stopLoading(); - store.onReset(); - history.navigate("/success"); - } + if (store?.isBroadcastBot) { + onMappingBotToSegment({ + queryParams: { + text: reqObj.startingMessage, + botId: res.data.result.id, + }, }) - .catch((err) => { - toast.error(err?.message); - store.stopLoading(); - }); + .then((res) => { + if (store?.isBroadcastBot) { + onSegmentCreate(); + } else { + store?.stopLoading(); + store.onReset(); + history.navigate("/success"); + } + }) + .catch((err) => { + toast.error(err?.message); + store.stopLoading(); + }); + } }) .catch((err) => { store?.stopLoading(); @@ -115,13 +118,6 @@ export const onSegmentCreate = () => { }); }; -export const afterBroadcastBotLogic = () => { - const store: any = useStore.getState(); - if (store?.conversationLogic.length <= store?.broadcastBotLogics.length) { - store?.setConversationLogic(store?.broadcastBotLogics); - onBotCreate(); - } -}; export const onStartConversation = (bot) => { const store: any = useStore.getState(); @@ -192,7 +188,7 @@ export const onCreateBroadcastBotLogic = () => { console.log({ store }); console.log({state:store.state}) for (const botLogic of store?.conversationLogic) { - console.log({ botLogic }); + const newBotLogic = { ...botLogic, adapter: process.env.REACT_APP_broadcastAdapterId, @@ -222,11 +218,8 @@ export const onCreateBroadcastBotLogic = () => { ], templateType: "JS_TEMPLATE_LITERALS", }, - }, ], - - }; // eslint-disable-next-line no-loop-func addLogic({ data: newBotLogic }) @@ -305,35 +298,38 @@ export const onBroadcastBotCreate=()=>{ } + + export const onBotUpdate = () => { const store: any = useStore.getState(); store?.startLoading(); const reqObj = { - ...store?.state, - isBroadcastBotEnabled: store?.isBroadcastBot, - users: [], - logic: [], + ...store?.editState, + id: store.state.id, }; - store?.userSegments.forEach((userSegment) => { - reqObj.users.push(userSegment.id); - }); - store?.conversationLogic.forEach((logic) => { - reqObj.logic.push(logic.id); - }); + + if (reqObj.startDate) { reqObj.startDate = moment(reqObj.startDate).format("YYYY-MM-DD"); } if (reqObj.endDate) { reqObj.endDate = moment(reqObj.endDate).format("YYYY-MM-DD"); } - + // const newData = omitBy(reqObj, isNull); + // console.log("bot update:", { reqObj, newData }); store?.startLoading(); updateBot(reqObj) .then((res) => { + console.log("bot update:", { res }); store?.stopLoading(); + toast.success("Bot Updated"); + store.stopLoading(); + store.onReset(); + history.navigate("/success"); }) .catch((err) => { + console.log("bot update:", { err }); store?.stopLoading(); console.log({ err }); }); diff --git a/src/api/getBots.ts b/src/api/getBots.ts index 6cebeca..87ca6c6 100644 --- a/src/api/getBots.ts +++ b/src/api/getBots.ts @@ -1,7 +1,7 @@ import axios from "axios"; import { searchBot } from "./urls"; import { getDefaultHeaders } from "./utils"; -import {omitBy,isNull} from 'lodash'; +import { omitBy, isNull } from "lodash"; export const getBots = (data: any) => { const url = searchBot; @@ -10,10 +10,17 @@ export const getBots = (data: any) => { ...getDefaultHeaders(), asset: "bot", }, - params: omitBy({ perPage: data.perPage, page: data.page ,name: data.name },isNull) , + params: omitBy( + { + perPage: data.perPage, + page: data.page, + name: data.name, + sortBy: data.sortBy, + orderBy: data.orderBy, + }, + isNull + ), }; return axios.get(url, config); }; - - diff --git a/src/api/updateBot.ts b/src/api/updateBot.ts index 638f419..c716b3f 100644 --- a/src/api/updateBot.ts +++ b/src/api/updateBot.ts @@ -1,6 +1,7 @@ import axios from "axios"; import { getUpdateBotUrl } from "./urls"; import { getDefaultHeaders } from "./utils"; +import {omit} from 'lodash' export const updateBot = (data: any) => { const url = getUpdateBotUrl(data?.id); @@ -11,5 +12,5 @@ export const updateBot = (data: any) => { }, }; - return axios.patch(url, data, config); + return axios.patch(url, omit (data,['id','segmentId']), config); }; diff --git a/src/components/addLogicModal/index.tsx b/src/components/addLogicModal/index.tsx index 5c14b8a..79b3ac3 100644 --- a/src/components/addLogicModal/index.tsx +++ b/src/components/addLogicModal/index.tsx @@ -81,6 +81,7 @@ const AddLogicModal: FC = ({ adapter: process.env.REACT_APP_adapterId, }; + addLogic({ data }) .then((res) => { const newLogic = [...logics, { ...res.data.result }]; @@ -180,7 +181,7 @@ const AddLogicModal: FC = ({ @@ -213,7 +214,7 @@ const AddLogicModal: FC = ({ = ({ compProps }) => { const { conversationLogic, onToggle } = compProps; + return (

Conversation Flow

diff --git a/src/components/conversationSetup/index.tsx b/src/components/conversationSetup/index.tsx index 9873b93..4fc2074 100644 --- a/src/components/conversationSetup/index.tsx +++ b/src/components/conversationSetup/index.tsx @@ -12,15 +12,10 @@ import "react-datepicker/dist/react-datepicker.css"; import { useStore } from "../../store"; import moment from "moment"; - const ConversationSetup: FC<{ compProps: any }> = ({ compProps }) => { const store: any = useStore(); - - const { - onChangeHandler, - errors - } = compProps; - + + const { onChangeHandler, errors, disabled } = compProps; const onDateChangeHandler = useCallback( (data) => { onChangeHandler({ target: data }); @@ -33,15 +28,57 @@ const ConversationSetup: FC<{ compProps: any }> = ({ compProps }) => { {/*

Conversation Setup

*/} +
+

Bot Icon

+ + {store?.state.botImage && ( + +
+ bot-icon +
+
+ )} + store?.setBotIcon(ev.target?.files?.[0])} + /> +
+
{errors.name && (
{errors?.name}
@@ -53,9 +90,9 @@ const ConversationSetup: FC<{ compProps: any }> = ({ compProps }) => { //@ts-ignore onChange={onChangeHandler} name="description" - value={store?.state?.description || ''} + value={store?.state?.description || ""} rows={4} - size='md' + size="md" /> {/*
Name Not Available @@ -67,8 +104,8 @@ const ConversationSetup: FC<{ compProps: any }> = ({ compProps }) => { type="text" onChange={onChangeHandler} name="purpose" - value={store?.state?.purpose || ''} - size='md' + value={store?.state?.purpose || ""} + size="md" /> {/*
Name Not Available @@ -81,7 +118,7 @@ const ConversationSetup: FC<{ compProps: any }> = ({ compProps }) => { onChange={onChangeHandler} name="startingMessage" value={store?.state?.startingMessage} - size='md' + size="md" /> {errors?.startingMessage && (
Message Not Available
@@ -97,62 +134,44 @@ const ConversationSetup: FC<{ compProps: any }> = ({ compProps }) => { label="Create Broadcast bot" size={5} defaultChecked + disabled={disabled} /> -
- {/*
+
+ {/*
Name Not Available
*/}
- -
- - onDateChangeHandler({ name: "startDate", value }) - } - customInput={} - /> + + onDateChangeHandler({ name: "startDate", value }) + } + customInput={} + />
- - onDateChangeHandler({ name: "endDate", value }) - } - customInput={} - /> -
- - -
-

Bot Icon

- store?.setBotIcon(ev.target?.files?.[0])} + onDateChangeHandler({ name: "endDate", value })} + customInput={} />
- {/* {state.botImage && - bot-icon - } */} ); }; diff --git a/src/components/table/index.tsx b/src/components/table/index.tsx index e8c0283..b1133ce 100644 --- a/src/components/table/index.tsx +++ b/src/components/table/index.tsx @@ -9,6 +9,7 @@ import { MDBDropdownToggle, MDBDropdownMenu, MDBDropdownItem, + MDBIcon, } from "mdb-react-ui-kit"; import { toast } from "react-hot-toast"; import { getBotUrl } from "../../utils"; @@ -35,7 +36,7 @@ export const Table: FC<{ data: Array }> = ({ data }) => { localStorage.setItem("botToEdit", JSON.stringify(data)); store?.setBotToEdit(data); store?.setConversationLogic(data?.logicIDs); - setTimeout(() => navigate("/add-bot?edit=true", { state: data }), 20); + setTimeout(() => navigate(`/add-bot?bot=${data.id}`, { state: data }), 20); }, [navigate, store] ); @@ -113,7 +114,7 @@ export const Table: FC<{ data: Array }> = ({ data }) => { }) )} > - Copy + @@ -123,21 +124,21 @@ export const Table: FC<{ data: Array }> = ({ data }) => { size="sm" onClick={onCopy(record?.id)} > - Copy + - - - Action + + + { ev.preventDefault(); - // onEdit(record); + onEdit(record); }} - disabled + > Edit diff --git a/src/index.css b/src/index.css index a67c038..cb7932a 100644 --- a/src/index.css +++ b/src/index.css @@ -27,4 +27,22 @@ code { } .form-label { +} + +.fas .fa-ellipsis-v::before { + +} + +.dropend .dropdown-toggle::after { + vertical-align: 0; +} +.no-icon > .dropend .dropdown-toggle::after { + display: none !important; + margin-left: .255em; + vertical-align: .255em; + content: ""; + border-top: .3em solid transparent; + border-right: 0; + border-bottom: .3em solid transparent; + border-left: .3em solid; } \ No newline at end of file diff --git a/src/pages/add/index.jsx b/src/pages/add/index.jsx index e482720..7ce7d72 100644 --- a/src/pages/add/index.jsx +++ b/src/pages/add/index.jsx @@ -19,108 +19,135 @@ import { toast } from "react-hot-toast"; import ConversationSetup from "../../components/conversationSetup"; import ConversationFlow from "../../components/conversationFlow"; -import { useLocation, useSearchParams } from "react-router-dom"; +import { useSearchParams } from "react-router-dom"; import { onBotCreate, onBotUpdate } from "../../api/api-util-functions"; import { useStore } from "../../store"; +import { getBotById } from "../../api/getBotById"; export const Add = () => { const store = useStore(); - const location = useLocation(); - const [isFirstLoad, setIsFirstLoad] = useState(true); - const [searchParams] = useSearchParams(); + const [searchParams] = useSearchParams(); const [isStep1, setIsStep1] = useState(true); + const [errors, setErrors] = useState({}); const [open, setOpen] = useState(false); - const [isEdit, setIsEdit] = useState(false); const onToggle = useCallback(() => setOpen((prev) => !prev), []); + const isEditParamAvailable = useMemo( + () => (searchParams.get("bot") ? true : false), + [searchParams] + ); + const onChangeHandler = useCallback( (ev) => { + if (isEditParamAvailable) { + store.setEditState({ + ...store.editState, + [ev.target.name]: ev.target.value, + }); + } store.setState({ ...store.state, [ev.target.name]: ev.target.value }); }, - [store] + [store, isEditParamAvailable] ); - const isEditParamAvailable = useMemo( - () => searchParams.get("edit") === "true", - [searchParams] + const onSubmitHandler = useCallback( + (ev) => { + ev.preventDefault(); + if (isEditParamAvailable) onBotUpdate(); + else onBotCreate(false, false); + }, + [isEditParamAvailable] ); - const onSubmitHandler = useCallback((ev) => { - ev.preventDefault(); - if(isEditParamAvailable ) - onBotUpdate(); - else onBotCreate(false, false); - }, [isEditParamAvailable]); - - useEffect(() => { - if (isEditParamAvailable && isFirstLoad) { - setIsEdit(true); - var data; - if (location.state) { - data = location.state; - } else if (localStorage.getItem("botToEdit")) { - data = JSON.parse(localStorage.getItem("botToEdit")); - } - store?.setState({ - // ...store?.state, - ...data, - startDate: new Date(data.startDate), - endDate: new Date(data.endDate), - description: data.description || "", - purpose: data.purpose || "", - }); - setIsFirstLoad(false); + if (searchParams.get("bot")) { + getBotById(searchParams.get("bot")) + .then((res) => { + const data = { + // ...store?.state, + ...res.data.result, + startDate: new Date(res?.data?.result?.startDate), + endDate: new Date(res?.data?.result?.endDate), + description: res?.data?.result?.description || "", + purpose: res?.data?.result?.purpose || "", + }; + console.log("venom res vv:", { data }); + store?.setState({ + ...data, + }); + store?.setBotToEdit(data); + store?.setConversationLogic(data?.logicIDs); + store?.setBotIcon(data?.botImage); + }) + .catch((error) => { + console.log("venom", { error }); + }); } - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isEditParamAvailable, location.state, store?.setState,isFirstLoad]); - - - const onCheckDuplicateName = useCallback(({ name }) => { - if (name !== "" && name!==store?.botToEdit?.name) - checkDuplicateName({ - name, - }).then((res) => { - - - if (res?.data?.result?.data?.length > 0) { - setErrors((prev) => ({ ...prev, name: "Name Not Available" })); - } else { - setErrors((prev) => ({ ...prev, name: null })); - } - }); - }, [store?.botToEdit?.name]); - - const onCheckDuplicateStartingMsg = useCallback(({ startingMessage }) => { - if (startingMessage !== "" && startingMessage!==store?.botToEdit?.startingMessage) - checkDuplicateName({ - startingMessage, - }).then((res) => { - if (res?.data?.result?.data?.length > 0) { - setErrors((prev) => ({ - ...prev, - startingMessage: "Staring Message Not Available", - })); - } else { - setErrors((prev) => ({ ...prev, startingMessage: null })); - } - }); - }, [store?.botToEdit?.startingMessage]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ + searchParams, + store?.setState, + store?.setBotToEdit, + store?.setConversationLogic, + store?.setBotIcon, + ]); + + const onCheckDuplicateName = useCallback( + ({ name }) => { + if (name !== "" && name !== store?.botToEdit?.name) { + checkDuplicateName({ + name, + }).then((res) => { + if (res?.data?.result?.data?.length > 0) { + setErrors((prev) => ({ ...prev, name: "Name Not Available" })); + } else { + setErrors((prev) => ({ ...prev, name: null })); + } + }); + } + }, + [store?.botToEdit] + ); + + const onCheckDuplicateStartingMsg = useCallback( + ({ startingMessage }) => { + if ( + startingMessage !== "" && + startingMessage !== store?.botToEdit?.startingMessage + ) + checkDuplicateName({ + startingMessage, + }).then((res) => { + if (res?.data?.result?.data?.length > 0) { + setErrors((prev) => ({ + ...prev, + startingMessage: "Staring Message Not Available", + })); + } else { + setErrors((prev) => ({ ...prev, startingMessage: null })); + } + }); + }, + [store?.botToEdit?.startingMessage] + ); useEffect(() => { onCheckDuplicateName({ name: store?.state.name }); onCheckDuplicateStartingMsg({ startingMessage: store?.state.startingMessage, }); + return () => { + setErrors({}); + }; }, [ onCheckDuplicateName, onCheckDuplicateStartingMsg, store?.state?.name, store?.state.startingMessage, + store?.state, ]); useEffect(() => { @@ -134,7 +161,7 @@ export const Add = () => { err.message || "Something went wrong in fetching segment count" ); }); - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [store?.state.segmentId, store?.setSegmentCount]); const compProps = useMemo( @@ -142,30 +169,52 @@ export const Add = () => { state: store?.state, onChangeHandler, errors, + disabled: isEditParamAvailable, isBroadcastBot: store?.isBroadcastBot, setIsBroadcastBot: store?.setIsBroadcastBot, setBotIcon: store?.setBotIcon, }), - [errors, onChangeHandler, store] + [ + errors, + isEditParamAvailable, + onChangeHandler, + store?.isBroadcastBot, + store?.setBotIcon, + store?.setIsBroadcastBot, + store?.state, + ] ); const step2CompProps = useMemo( - () => ({ conversationLogic: store?.conversationLogic, onToggle }), - [store?.conversationLogic, onToggle] + () => ({ + conversationLogic: store?.conversationLogic, + onToggle, + disabled: isEditParamAvailable, + }), + [store?.conversationLogic, onToggle, isEditParamAvailable] ); - const isNextDisabled = useMemo( - () => + const isNextDisabled = useMemo(() => { + if (isEditParamAvailable) { + return false; + } + return ( Object.values(errors).some((v) => v !== null) || Object.values( store?.isBroadcastBot ? store?.state : omit(store?.state, ["segmentId"]) ).some((v) => v === "" || v === undefined || v === null) || store?.botIcon === "" || - store?.botIcon === null, - [errors, store?.state, store?.botIcon, store?.isBroadcastBot] - ); + store?.botIcon === null + ); + }, [ + errors, + store?.state, + store?.botIcon, + store?.isBroadcastBot, + isEditParamAvailable, + ]); return ( - + <> @@ -181,9 +230,12 @@ export const Add = () => { -
ev.preventDefault()}> - {isStep1 && } - {!isStep1 && } + ev.preventDefault()}> + {isStep1 ? ( + + ) : ( + + )} @@ -204,7 +256,7 @@ export const Add = () => { onClick={onSubmitHandler} disabled={store?.conversationLogic.length === 0} > - {isEditParamAvailable ? 'Update' : 'Submit'} + {isEditParamAvailable ? "Update" : "Submit"} )} diff --git a/src/pages/dashboard/index.tsx b/src/pages/dashboard/index.tsx index a3e57a0..72cc175 100644 --- a/src/pages/dashboard/index.tsx +++ b/src/pages/dashboard/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { getBots } from "../../api/getBots"; import { toast } from "react-hot-toast"; import { Table } from "../../components/table"; @@ -6,6 +6,10 @@ import { MDBBtn, MDBCol, MDBContainer, + MDBDropdown, + MDBDropdownItem, + MDBDropdownMenu, + MDBDropdownToggle, MDBIcon, MDBRow, } from "mdb-react-ui-kit"; @@ -13,39 +17,66 @@ import Pagination from "../../components/pagination"; import { useNavigate } from "react-router-dom"; import { useStore } from "../../store"; +const getSortTypeLabel = (value: string) => { + switch (value) { + case "status": + return "Status"; + case "createdAt": + return "Date Created"; + case "endDate": + return "Date Expired"; + default: + return "Name"; + } +}; + export const Dashboard = () => { const store: any = useStore(); const [page, setPage] = useState(1); - const [searchText, setSearchText] = useState(''); + const [searchText, setSearchText] = useState(""); const [perPage, setPerPage] = useState(10); + const [sortBy, setSortBy] = useState("createdAt"); + const [orderBy, setOrderBy] = useState("desc"); const [botList, setBotList] = useState([]); const [totalRecords, setTotalRecords] = useState(0); const navigate = useNavigate(); - useEffect(() => { store?.startLoading(); - const data = searchText.length > 0 ? {name:searchText} : {perPage, page}; + const data = + searchText.length > 0 + ? { name: searchText, sortBy, orderBy } + : { perPage, page, sortBy, orderBy }; getBots(data) .then((res) => { store?.stopLoading(); setBotList(res?.data?.result?.data); setTotalRecords(res?.data?.result?.totalCount || 0); - if(searchText.length >0 ){ + if (searchText.length > 0) { setPage(1); - setPerPage(10) + setPerPage(10); } }) .catch((err) => { store?.stopLoading(); toast.error(err.message); }); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [page, perPage, store.startLoading, store?.stopLoading,searchText]); - - + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [page, perPage, store.startLoading, store?.stopLoading, searchText,orderBy,sortBy]); + + const onSortChange = useCallback( + (sortValue) => () => { + setSortBy(sortValue); + }, + [] + ); + + const sortLabel = useMemo(() => getSortTypeLabel(sortBy), [sortBy]); + const orderByIcon = useMemo( + () => (orderBy === "desc" ? "sort-amount-down" : "sort-amount-up"), + [orderBy] + ); return ( @@ -57,24 +88,82 @@ export const Dashboard = () => { placeholder="Search" aria-label="Search" value={searchText} - onChange={ev=>setSearchText(ev.target.value)} + onChange={(ev) => setSearchText(ev.target.value)} /> Search
- navigate("/add-bot")}> + + + {sortLabel}   + + + + Name + + + Status + + + Date Created + + + Date Expired + + + + + + + +   + + + setOrderBy("desc")} + > + Descending + + setOrderBy("asc")} + > + Ascending + + + + + navigate("/add-bot")} className="mx-2">    Add - {/* null} className="mx-2"> + {/* null} className="mx-2">    Refresh */} -
-
+
({ endDate: null, startingMessage: "", }, + editState:{ + }, + setEditState:(newValue)=>set({editState:newValue}), setState: (newValue) => set({ state: newValue }), setCadencePerPage:(newValue)=>set({cadencePerPage:newValue}), segmentCount: 100, From 62f881f61ead20d14c6e4cd6a172761de9671d4d Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Tue, 8 Aug 2023 12:36:47 +0530 Subject: [PATCH 09/10] Feat media management (#47) * feat: multiple media support added * feat: disable bot integrated --- src/components/addLogicModal/index.tsx | 91 ++++++++++++++++++++++++-- src/components/addLogicModal/style.css | 36 ++++++++++ src/components/fileModal/index.tsx | 47 +++++++++++++ src/components/table/index.tsx | 35 ++++++---- 4 files changed, 188 insertions(+), 21 deletions(-) create mode 100644 src/components/addLogicModal/style.css create mode 100644 src/components/fileModal/index.tsx diff --git a/src/components/addLogicModal/index.tsx b/src/components/addLogicModal/index.tsx index 79b3ac3..7e515ae 100644 --- a/src/components/addLogicModal/index.tsx +++ b/src/components/addLogicModal/index.tsx @@ -14,6 +14,7 @@ import { MDBContainer, MDBCol, MDBSpinner, + MDBIcon, } from "mdb-react-ui-kit"; import { toast } from "react-hot-toast"; import { uploadForm } from "../../api/uploadForm"; @@ -21,6 +22,9 @@ import { addLogic } from "../../api/addLogic"; import { omitBy, isNull } from "lodash"; import { getUploadErrorMsg } from "../../utils"; import { useStore } from "../../store"; +import "./style.css"; +import FileModal from "../fileModal"; + const AddLogicModal: FC = ({ open, activeLogic = {}, @@ -31,6 +35,7 @@ const AddLogicModal: FC = ({ const [logics, setLogics] = useState([]); const [form, setForm] = useState(null); const [media, setMedia] = useState(null); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [cadencePerPage, setCadencePerPage] = useState(100); const [formId, setFormId] = useState(""); const [modalState, setModalState] = useState({ ...activeLogic }); @@ -104,10 +109,11 @@ const AddLogicModal: FC = ({ }, []); const onMediaChange = useCallback((event: any) => { - if (!event.target.files.length) { + const files = Array.from(event.target.files); + if (!files.length) { toast.error("No File Selected"); } - setMedia(event.target.files); + setMedia(files); }, []); const onFormUpload = useCallback( @@ -150,7 +156,36 @@ const AddLogicModal: FC = ({ ), [form, formId, modalState] ); - console.log("perpage_comp:",store?.cadencePerPage) + + // Handle file selection + const handleFileChange = (e) => { + if (!e.target.files.length) { + toast.error("No File Selected"); + } + const files = Array.from(e.target.files); + setMedia(files); + }; + + // Handle file removal + const handleFileRemove = (fileName) => { + //setIsDeleteModalOpen(true) + setMedia((prevSelectedFiles) => + prevSelectedFiles.filter((file) => file.name !== fileName) + ); + }; + + const confirmDelete = (ev, fileName) => { + const shouldDelete = window.confirm( + "Are you sure you want to delete this media?" + ); + if (shouldDelete) { + handleFileRemove(fileName); + } else { + ev.preventDefault(); + } + }; + + console.log({ media }); if (!open) return null; return ( @@ -197,8 +232,6 @@ const AddLogicModal: FC = ({ > - {/* - */} @@ -211,16 +244,56 @@ const AddLogicModal: FC = ({ onChange={onOdkFormChange} /> + + + + {/* {renderSelectedFiles()} */} +
+
+ {media?.length > 0 ? ( + media.map((file) => ( +
+ + + {file.name} + + + {/* */} + + confirmDelete(ev,file.name)} + > + + +
+ )) + ) : ( +

No files selected.

+ )} +
+
+
@@ -261,6 +334,10 @@ const AddLogicModal: FC = ({ + setIsDeleteModalOpen(false)} + /> ); }; diff --git a/src/components/addLogicModal/style.css b/src/components/addLogicModal/style.css new file mode 100644 index 0000000..311b917 --- /dev/null +++ b/src/components/addLogicModal/style.css @@ -0,0 +1,36 @@ +/* FilePicker.css */ + +.file-picker { + /* width: 300px; */ + margin: auto; + + } + + .selected-files { + border: 1px solid #ccc; + border-radius: 5px; + padding: 10px; + } + + + .file-name { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 70%; + } + + .remove-btn { + background-color: #ff4444; + color: white; + border: none; + border-radius: 5px; + padding: 5px 10px; + cursor: pointer; + } + + .remove-btn:hover { + background-color: #ff0000; + } + \ No newline at end of file diff --git a/src/components/fileModal/index.tsx b/src/components/fileModal/index.tsx new file mode 100644 index 0000000..b14c29c --- /dev/null +++ b/src/components/fileModal/index.tsx @@ -0,0 +1,47 @@ +import { useState } from "react"; + +import { + MDBBtn, + MDBModal, + MDBModalDialog, + MDBModalContent, + MDBModalHeader, + MDBModalTitle, + MDBModalBody, + MDBModalFooter, +} from "mdb-react-ui-kit"; + +const FileModal = ({open,onClose}) => { + const [basicModal, setBasicModal] = useState(false); + const toggleShow = () => onClose(); + + return ( + + + + + Delete Media + + + + + + + + + + Close + + Save changes + + + + + ); +}; + +export default FileModal; diff --git a/src/components/table/index.tsx b/src/components/table/index.tsx index b1133ce..cf9d19e 100644 --- a/src/components/table/index.tsx +++ b/src/components/table/index.tsx @@ -16,6 +16,7 @@ import { getBotUrl } from "../../utils"; import { useNavigate } from "react-router-dom"; import { startConversation } from "../../api/startConversation"; import { useStore } from "../../store"; +import { updateBot } from "../../api/updateBot"; export const Table: FC<{ data: Array }> = ({ data }) => { const navigate = useNavigate(); @@ -32,7 +33,7 @@ export const Table: FC<{ data: Array }> = ({ data }) => { ); const onEdit = useCallback( - (data) => { + (data) => { localStorage.setItem("botToEdit", JSON.stringify(data)); store?.setBotToEdit(data); store?.setConversationLogic(data?.logicIDs); @@ -42,14 +43,22 @@ export const Table: FC<{ data: Array }> = ({ data }) => { ); const onEnable = useCallback((data) => { - startConversation(data) - .then((res) => { - toast.success("Bot Enabled"); - }) - .catch((err) => { - toast.error(err.message); - }); - }, []); + console.log({data}) + store.startLoading(); + const newValue={id:data.id , status : data.status === 'DISABLED' ? 'ENABLED' : 'DISABLED'} + + updateBot(newValue).then(res=>{ + store.stopLoading(); + const toastMsg= data.status === 'DISABLED' ? 'Bot Enabled Succesfully' : 'Bot Disabled Succesfully' + toast.success(toastMsg); + window.location.reload(); + console.log({res}) + }).catch(err=>{ + store.stopLoading(); + toast.error(`Error occured in updating bot-${err.message}`) + console.log({err}); + }) + }, [store]); return ( @@ -142,16 +151,14 @@ export const Table: FC<{ data: Array }> = ({ data }) => { > Edit - {/* Delete + { ev.preventDefault(); onEnable(record); - }}>Enable */} + }}>{record?.status === 'DISABLED' ? 'Enable' : 'Disable'} From 027e83f094c1d6ac08ab9983a2b960a2f9e4739b Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Fri, 18 Aug 2023 14:00:27 +0530 Subject: [PATCH 10/10] chore: ui update for diksha bot --- src/components/conversationSetup/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/conversationSetup/index.tsx b/src/components/conversationSetup/index.tsx index 4fc2074..17c0d30 100644 --- a/src/components/conversationSetup/index.tsx +++ b/src/components/conversationSetup/index.tsx @@ -131,7 +131,7 @@ const ConversationSetup: FC<{ compProps: any }> = ({ compProps }) => { checked={store?.isBroadcastBot} onChange={(ev) => store?.setIsBroadcastBot(ev.target.checked)} id="flexCheckDefault" - label="Create Broadcast bot" + label="Create Whatsapp bot" size={5} defaultChecked disabled={disabled} @@ -141,7 +141,7 @@ const ConversationSetup: FC<{ compProps: any }> = ({ compProps }) => { Name Not Available */} -
+ {/*
= ({ compProps }) => { value={store?.state?.segmentId} disabled={!store?.isBroadcastBot || disabled} /> -
+
*/}