diff --git a/mocks/handler.js b/mocks/handler.js
index fbb803a..232c91e 100644
--- a/mocks/handler.js
+++ b/mocks/handler.js
@@ -1,13 +1,15 @@
-import {userHandler} from "./handlers/user";
-import {permissionsHandler} from "./handlers/permissions";
-import {rolesHandler} from "./handlers/roles";
-import {provincesHandler} from "./handlers/provinces";
-import {expertsHandler} from "./handlers/experts";
+import { userHandler } from "./handlers/user";
+import { permissionsHandler } from "./handlers/permissions";
+import { rolesHandler } from "./handlers/roles";
+import { provincesHandler } from "./handlers/provinces";
+import { expertsHandler } from "./handlers/experts";
+import { categoriesHandler } from "./handlers/categories";
export const handler = [
...userHandler,
...permissionsHandler,
...rolesHandler,
...provincesHandler,
- ...expertsHandler
-]
\ No newline at end of file
+ ...expertsHandler,
+ ...categoriesHandler,
+];
diff --git a/mocks/handlers/categories.js b/mocks/handlers/categories.js
new file mode 100644
index 0000000..6864331
--- /dev/null
+++ b/mocks/handlers/categories.js
@@ -0,0 +1,25 @@
+import { rest } from "msw";
+import { GET_CATEGORY } from "@/core/data/apiRoutes";
+
+export const categoriesHandler = [
+ rest.get(GET_CATEGORY, (req, res, ctx) => {
+ return res(
+ ctx.json({
+ data: [
+ {
+ category_id: 1,
+ category_name: "اطلاعات راه",
+ subcategory_id: 1,
+ subcategory_name: "اطلاعات باز و بسته",
+ },
+ {
+ category_id: 3,
+ category_name: "سایر",
+ subcategory_id: 2,
+ subcategory_name: "مزاحم",
+ },
+ ],
+ })
+ );
+ }),
+];
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/CallActionCategoriesButton.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/CallActionCategoriesButton.jsx
new file mode 100644
index 0000000..d7c70f6
--- /dev/null
+++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/CallActionCategoriesButton.jsx
@@ -0,0 +1,21 @@
+import { Button, Stack } from "@mui/material";
+import useCategories from "@/lib/callWidget/hooks/useCategories";
+
+const CallActionCategoriesButton = ({ category, tab }) => {
+ const { setActiveCategoryID } = useCategories();
+
+ return (
+
+
+
+ );
+};
+export default CallActionCategoriesButton;
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/__test__/CallActionCategoriesButton.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/__test__/CallActionCategoriesButton.test.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/index.jsx
new file mode 100644
index 0000000..c40d31c
--- /dev/null
+++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionCategories/index.jsx
@@ -0,0 +1,15 @@
+import { Stack } from "@mui/material";
+import useCategories from "@/lib/callWidget/hooks/useCategories";
+import CallActionCategoriesButton from "./CallActionCategoriesButton";
+
+const CallActionsCategories = ({ tab }) => {
+ const { categoryLists } = useCategories();
+ return (
+
+ {categoryLists.map((category) => {
+ return ;
+ })}
+
+ );
+};
+export default CallActionsCategories;
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/CallActionSubcategoriesButton.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/CallActionSubcategoriesButton.jsx
new file mode 100644
index 0000000..4051511
--- /dev/null
+++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/CallActionSubcategoriesButton.jsx
@@ -0,0 +1,33 @@
+import { Button, Stack } from "@mui/material";
+import useCategories from "@/lib/callWidget/hooks/useCategories";
+import useRequest from "@/lib/app/hooks/useRequest";
+import { CALL_ACTION } from "@/core/data/apiRoutes";
+import useAnswers from "@/lib/callWidget/hooks/useAnswers";
+
+const CallActionSubcategoriesButton = ({ sub_category, tab }) => {
+ const requestServer = useRequest({ auth: true });
+ const { closeAnswerTab } = useAnswers();
+ const handleSubcategoryButton = () => {
+ requestServer(`${CALL_ACTION}/${tab.id}`, "post", {
+ data: {
+ category_id: sub_category.category_id,
+ subcategory_id: sub_category.subcategory_id,
+ },
+ success: {
+ notification: { show: false },
+ },
+ })
+ .then(() => {
+ closeAnswerTab(tab.id);
+ })
+ .catch(() => {});
+ };
+ return sub_category.category_id === tab.active_category_id ? (
+
+
+
+ ) : null;
+};
+export default CallActionSubcategoriesButton;
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/__test__/CallActionSubcategoriesButton.test.js b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/__test__/CallActionSubcategoriesButton.test.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/index.jsx
new file mode 100644
index 0000000..7e270bb
--- /dev/null
+++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/index.jsx
@@ -0,0 +1,15 @@
+import useCategories from "@/lib/callWidget/hooks/useCategories";
+import { Stack } from "@mui/material";
+import CallActionSubcategoriesButton from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/CallActionSubcategories/CallActionSubcategoriesButton";
+
+const CallActionsSubcategories = ({ tab }) => {
+ const { subCategoryLists } = useCategories();
+ return (
+
+ {subCategoryLists.map((sub_category, index) => {
+ return ;
+ })}
+
+ );
+};
+export default CallActionsSubcategories;
diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/index.jsx
index d1a68f7..d713c76 100644
--- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/index.jsx
+++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/index.jsx
@@ -1,7 +1,13 @@
-const CallActions = ({tab}) => {
+import CallActionsCategories from "./CallActionCategories";
+import CallActionSubcategoriesButton from "./CallActionSubcategories/CallActionSubcategoriesButton";
+
+function CallActions({ tab }) {
return (
- <>CallActions - {tab.id}>
- )
+ <>
+
+
+ >
+ );
}
-export default CallActions
+export default CallActions;
diff --git a/src/core/data/apiRoutes.js b/src/core/data/apiRoutes.js
index 19534ca..7df6b2e 100644
--- a/src/core/data/apiRoutes.js
+++ b/src/core/data/apiRoutes.js
@@ -25,21 +25,16 @@ export const GET_USER = BASE_URL + "/api/profile/info";
//user data
//sidebar notification
-export const GET_SIDEBAR_NOTIFICATION = BASE_URL + "/dashboard/notification"
+export const GET_SIDEBAR_NOTIFICATION = BASE_URL + "/dashboard/notification";
//sidebar notification
// role management
-export const GET_ROLES =
- BASE_URL + "/api/roles"
-export const ADD_ROLE =
- BASE_URL + "/api/roles"
-export const UPDATE_ROLE =
- BASE_URL + "/api/roles"
-export const DELETE_ROLE =
- BASE_URL + "/api/roles"
+export const GET_ROLES = BASE_URL + "/api/roles";
+export const ADD_ROLE = BASE_URL + "/api/roles";
+export const UPDATE_ROLE = BASE_URL + "/api/roles";
+export const DELETE_ROLE = BASE_URL + "/api/roles";
-export const GET_PERMISSIONS_LIST =
- BASE_URL + "/api/permissions/list"
+export const GET_PERMISSIONS_LIST = BASE_URL + "/api/permissions/list";
//role management
//expert management
@@ -47,4 +42,9 @@ export const GET_EXPERTS = BASE_URL + "/api/users";
export const ADD_EXPERT = BASE_URL + "/api/users";
export const UPDATE_EXPERT = BASE_URL + "/api/users";
export const DELETE_EXPERT = BASE_URL + "/api/users";
-//expert management
\ No newline at end of file
+//expert management
+
+//call action history
+export const GET_CATEGORY = BASE_URL + "/api/categories";
+export const CALL_ACTION = BASE_URL + "/api/calls";
+//call action history
diff --git a/src/lib/callWidget/contexts/answers.jsx b/src/lib/callWidget/contexts/answers.jsx
index b5c9c0b..4aa3c3c 100644
--- a/src/lib/callWidget/contexts/answers.jsx
+++ b/src/lib/callWidget/contexts/answers.jsx
@@ -1,31 +1,101 @@
-import {createContext, useReducer, useState} from "react";
+import { createContext, useEffect, useReducer, useState } from "react";
+import { GET_CATEGORY } from "@/core/data/apiRoutes";
+import useRequest from "@/lib/app/hooks/useRequest";
const reducer = (state, action) => {
switch (action.type) {
case "CHANGE_ACTIVE_TAB":
- return state.map((answer, index) => action.newValue === index ? {...answer, active: true} : {
- ...answer,
- active: false
- });
+ return state.map((answer, index) =>
+ action.newValue === index
+ ? { ...answer, active: true }
+ : {
+ ...answer,
+ active: false,
+ }
+ );
case "CHANGE_LIST":
- return [...action.newList]
+ return [...action.newList];
+ case "CHANGE_ACTIVE_ID":
+ return state.map((answer, index) =>
+ action.tab_id === answer.id
+ ? {
+ ...answer,
+ active_category_id: action.category_id,
+ }
+ : { ...answer }
+ );
default:
return state;
}
-}
-export const AnswersContext = createContext()
-export const AnswersProvider = ({children}) => {
- const [openCallDialog, setOpenCallDialog] = useState(false)
- const [activeTab, setActiveTab] = useState(0)
- const [state, dispatch] = useReducer(reducer, []);
+};
- return {children}
-}
+const submission = (handleCategories, operation) => {
+ switch (operation.type) {
+ case "SET_CATEGORIES":
+ return { ...handleCategories, categoryLists: operation.categoriesByAPI };
+ case "SET_SUBCATEGORIES":
+ return { ...handleCategories, subCategoryLists: operation.subCategoriesByAPI };
+ default:
+ return handleCategories;
+ }
+};
+
+export const AnswersContext = createContext();
+export const AnswersProvider = ({ children }) => {
+ const requestServer = useRequest({ auth: true, notification: false });
+ const [openCallDialog, setOpenCallDialog] = useState(false);
+ const [activeTab, setActiveTab] = useState(0);
+ const [handleCategories, operation] = useReducer(submission, {
+ categoryLists: [],
+ subCategoryLists: [],
+ });
+ const [state, dispatch] = useReducer(reducer, [
+ {
+ id: 1,
+ phone_number: "09134849737",
+ date: new Date(),
+ active: true,
+ active_category_id: 1,
+ },
+ {
+ id: 2,
+ phone_number: "09134849737",
+ date: new Date(),
+ active: false,
+ active_category_id: 2,
+ },
+ ]);
+
+ useEffect(() => {
+ requestServer(GET_CATEGORY, "get")
+ .then(({ data }) => {
+ const subCategoriesByAPI = data.data;
+ const categoriesByAPI = subCategoriesByAPI.reduce((accumulator, currentValue) => {
+ if (!accumulator.find((item) => item.category_id === currentValue.category_id)) {
+ accumulator.push(currentValue);
+ }
+ return accumulator;
+ }, []);
+ operation({ type: "SET_CATEGORIES", categoriesByAPI });
+ operation({ type: "SET_SUBCATEGORIES", subCategoriesByAPI });
+ })
+ .catch(() => {});
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/lib/callWidget/contexts/categories.jsx b/src/lib/callWidget/contexts/categories.jsx
new file mode 100644
index 0000000..533dfc3
--- /dev/null
+++ b/src/lib/callWidget/contexts/categories.jsx
@@ -0,0 +1,59 @@
+import { createContext, useCallback, useEffect, useReducer } from "react";
+import useRequest from "@/lib/app/hooks/useRequest";
+import { GET_CATEGORY } from "@/core/data/apiRoutes";
+
+const reducer = (state, action) => {
+ switch (action.type) {
+ case "CHANGE_ACTIVE_ID":
+ return { ...state, active_id: action.id };
+ case "SET_CATEGORIES":
+ return { ...state, categoryLists: action.cat };
+ case "SET_SUBCATEGORIES":
+ return { ...state, subCategoryLists: action.subCat };
+ default:
+ return state;
+ }
+};
+export const CategoriesContext = createContext();
+
+export const CategoriesProvider = ({ children }) => {
+ const requestServer = useRequest({ auth: true, notification: false });
+ const [state, dispatch] = useReducer(reducer, {
+ categoryLists: [],
+ subCategoryLists: [],
+ active_id: null,
+ });
+
+ useEffect(() => {
+ requestServer(GET_CATEGORY, "get")
+ .then(({ data }) => {
+ const subCat = data.data;
+ const cat = subCat.reduce((accumulator, currentValue) => {
+ if (!accumulator.find((item) => item.category_id === currentValue.category_id)) {
+ accumulator.push(currentValue);
+ }
+ return accumulator;
+ }, []);
+ dispatch({ type: "SET_CATEGORIES", cat });
+ dispatch({ type: "SET_SUBCATEGORIES", subCat });
+ })
+ .catch(() => {});
+ }, []);
+
+ const setCategoryID = useCallback((id) => {
+ dispatch({ type: "CHANGE_ACTIVE_ID", id });
+ });
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/lib/callWidget/hooks/useAnswers.jsx b/src/lib/callWidget/hooks/useAnswers.jsx
index 68f8b46..149b1d3 100644
--- a/src/lib/callWidget/hooks/useAnswers.jsx
+++ b/src/lib/callWidget/hooks/useAnswers.jsx
@@ -1,38 +1,46 @@
-import {useContext} from "react";
-import {AnswersContext} from "@/lib/callWidget/contexts/answers";
+import { useContext } from "react";
+import { AnswersContext } from "@/lib/callWidget/contexts/answers";
const useAnswers = () => {
- const {state, dispatch, activeTab, setActiveTab} = useContext(AnswersContext)
+ const { state, dispatch, activeTab, setActiveTab } = useContext(AnswersContext);
const changeActiveTabAnswers = (newValue) => {
- dispatch({type: 'CHANGE_ACTIVE_TAB', newValue})
- setActiveTab(newValue)
- }
+ dispatch({ type: "CHANGE_ACTIVE_TAB", newValue });
+ setActiveTab(newValue);
+ };
const newAnswerTab = (data) => {
const newAnswer = {
id: data.id,
phone_number: data.phone_number,
date: new Date(),
- active: true
- }
- const newList = [...state, newAnswer]
- dispatch({type: 'CHANGE_LIST', newList})
- changeActiveTabAnswers(newList.length - 1)
- }
+ active: true,
+ active_category_id: null,
+ };
+ const newList = [...state, newAnswer];
+ dispatch({ type: "CHANGE_LIST", newList });
+ changeActiveTabAnswers(newList.length - 1);
+ };
const closeAnswerTab = (id) => {
- const index = state.findIndex(answer => answer.id === id)
- const newIndex = index === 0 ? 0 : index - 1
- const newList = [...state]
+ const index = state.findIndex((answer) => answer.id === id);
+ const newIndex = index === 0 ? 0 : index - 1;
+ const newList = [...state];
newList.splice(index, 1);
if (newList.length !== 0) {
- newList[newIndex].active = true
- setActiveTab(newIndex)
+ newList[newIndex].active = true;
+ setActiveTab(newIndex);
}
- dispatch({type: 'CHANGE_LIST', newList})
- }
+ dispatch({ type: "CHANGE_LIST", newList });
+ };
- return {answersList: state, activeTab, setActiveTab, changeActiveTabAnswers, closeAnswerTab, newAnswerTab}
-}
+ return {
+ answersList: state,
+ activeTab,
+ setActiveTab,
+ changeActiveTabAnswers,
+ closeAnswerTab,
+ newAnswerTab,
+ };
+};
-export default useAnswers
\ No newline at end of file
+export default useAnswers;
diff --git a/src/lib/callWidget/hooks/useCategories.jsx b/src/lib/callWidget/hooks/useCategories.jsx
new file mode 100644
index 0000000..423bd67
--- /dev/null
+++ b/src/lib/callWidget/hooks/useCategories.jsx
@@ -0,0 +1,17 @@
+import { useContext } from "react";
+import { AnswersContext } from "@/lib/callWidget/contexts/answers";
+
+const useCategories = () => {
+ const { categoryLists, subCategoryLists, active_category_id, dispatch } = useContext(AnswersContext);
+
+ const setActiveCategoryID = (tab_id, category_id) => {
+ dispatch({ type: "CHANGE_ACTIVE_ID", tab_id, category_id });
+ };
+ return {
+ categoryLists,
+ subCategoryLists,
+ active_category_id,
+ setActiveCategoryID,
+ };
+};
+export default useCategories;