From 77f5c86a0d31635da6bae9309879269e5ec165af Mon Sep 17 00:00:00 2001 From: AmirHossein Mahmoodi Date: Sat, 7 Oct 2023 15:03:20 +0330 Subject: [PATCH 1/3] CFE-22 fixed bug network hook and component --- src/core/components/NetworkComponent.jsx | 7 +++---- src/lib/app/hooks/useNetwork.jsx | 26 +----------------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/core/components/NetworkComponent.jsx b/src/core/components/NetworkComponent.jsx index 8ebbb68..22d4620 100644 --- a/src/core/components/NetworkComponent.jsx +++ b/src/core/components/NetworkComponent.jsx @@ -6,13 +6,13 @@ import WifiOffIcon from '@mui/icons-material/WifiOff'; import {useTranslations} from "next-intl"; const NetworkComponent = () => { - const toastId = useRef(null); + const networkToastId = useRef(null); const network = useNetwork() const t = useTranslations() useEffect(() => { if (network.online) { - toast.update(toastId.current, { + toast.update(networkToastId.current, { type: toast.TYPE.SUCCESS, render: t('online_message'), autoClose: 2000, @@ -22,8 +22,7 @@ const NetworkComponent = () => { }); return } - toast.dismiss() - toastId.current = toast.warn(t('offline_message'), { + networkToastId.current = toast.warn(t('offline_message'), { autoClose: false, closeButton: false, closeOnClick: false, icon: }) }, [network.online]); diff --git a/src/lib/app/hooks/useNetwork.jsx b/src/lib/app/hooks/useNetwork.jsx index 84e2950..9c436a5 100644 --- a/src/lib/app/hooks/useNetwork.jsx +++ b/src/lib/app/hooks/useNetwork.jsx @@ -1,29 +1,5 @@ import {useEffect, useState} from "react"; -function getNetworkConnection() { - return ( - navigator.connection || - navigator.mozConnection || - navigator.webkitConnection || - null - ); -} - -function getNetworkConnectionInfo() { - const connection = getNetworkConnection(); - if (!connection) { - return {}; - } - return { - rtt: connection.rtt, - type: connection.type, - saveData: connection.saveData, - downLink: connection.downLink, - downLinkMax: connection.downLinkMax, - effectiveType: connection.effectiveType, - }; -} - function useNetwork() { const [state, setState] = useState(() => { return { @@ -51,7 +27,7 @@ function useNetwork() { window.removeEventListener("offline", handleOffline); }; }, []); - + return state; } From 05c5e13c6386e229ad4e53171af8bcf9ffc086f8 Mon Sep 17 00:00:00 2001 From: AmirHossein Mahmoodi Date: Sat, 7 Oct 2023 15:03:57 +0330 Subject: [PATCH 2/3] CFE-22 fixed bug project --- src/layouts/MuiLayout.jsx | 15 ++++++--------- src/lib/app/contexts/user.jsx | 6 ------ src/pages/_app.jsx | 30 +++++++++++++++--------------- 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/layouts/MuiLayout.jsx b/src/layouts/MuiLayout.jsx index 6dcd3ed..eba3449 100644 --- a/src/layouts/MuiLayout.jsx +++ b/src/layouts/MuiLayout.jsx @@ -22,26 +22,23 @@ const MuiLayout = ({children, isBot}) => { { export const UserContext = createContext(); export const UserProvider = ({children}) => { - const socket = useSocket() const [state, dispatch] = useReducer(reducer, initialUser); const clearUser = useCallback(() => { @@ -102,16 +100,12 @@ export const UserProvider = ({children}) => { clearUser(); changeAuthState(false); changeLanguageState(false); - - socket.auth.token = "" return; } getUser((data) => { changeUser(data); changeAuthState(true); changeLanguageState(true); - - socket.auth.token = data.telephone_id }); }, [state.token]); diff --git a/src/pages/_app.jsx b/src/pages/_app.jsx index fe249a6..c5fad77 100644 --- a/src/pages/_app.jsx +++ b/src/pages/_app.jsx @@ -12,22 +12,22 @@ import {SocketProvider} from "@/lib/app/contexts/socket"; const App = ({Component, pageProps}) => { return (<> - - - - - - {pageProps.messages ? : ''} - - + + + + + {pageProps.messages ? : ''} + + + - - - - - - - + + + + + + + ) }; From b0766f13461f1c337b8bb2ad1c2e80cd085e89a1 Mon Sep 17 00:00:00 2001 From: AmirHossein Mahmoodi Date: Sat, 7 Oct 2023 15:04:40 +0330 Subject: [PATCH 3/3] CFE-22 implementation of socket and dialog and button call widget --- public/locales/fa/app.json | 2 + .../Dashboard/CallWidget/CallWidgetButton.jsx | 6 ++- .../CallTabPanel/CallActions/index.jsx | 7 +++ .../CallTabPanel/CallHistory/index.jsx | 7 +++ .../CallTabs/CallTabPanel/index.jsx | 19 +++++++ .../CallTabs/CallTabsList/CallTabLabel.jsx | 23 ++++++++ .../CallTabs/CallTabsList/index.jsx | 27 ++++++++++ .../CallWidgetDialog/CallTabs/index.jsx | 17 ++++++ .../CallWidget/CallWidgetDialog/index.jsx | 52 +++++++++++++----- .../layouts/Dashboard/CallWidget/index.jsx | 25 ++++++--- src/core/components/StyledFab.jsx | 1 - src/lib/app/contexts/socket.jsx | 54 ++++++++++++++++++- src/lib/callWidget/contexts/answers.jsx | 31 +++++++++++ src/lib/callWidget/hooks/useAnswers.jsx | 38 +++++++++++++ src/lib/callWidget/hooks/useCallDialog.jsx | 10 ++++ 15 files changed, 295 insertions(+), 24 deletions(-) create mode 100644 src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/index.jsx create mode 100644 src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/index.jsx create mode 100644 src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/index.jsx create mode 100644 src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabLabel.jsx create mode 100644 src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/index.jsx create mode 100644 src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/index.jsx create mode 100644 src/lib/callWidget/contexts/answers.jsx create mode 100644 src/lib/callWidget/hooks/useAnswers.jsx create mode 100644 src/lib/callWidget/hooks/useCallDialog.jsx diff --git a/public/locales/fa/app.json b/public/locales/fa/app.json index e813849..7366af7 100644 --- a/public/locales/fa/app.json +++ b/public/locales/fa/app.json @@ -15,6 +15,8 @@ "between": "میان", "online_message": "شما به اینترنت وصل هستید", "offline_message": "اتصال شما به اینترنت قطع شده است", + "socket_is_connect_message": "شما به سوکت وصل هستید", + "socket_is_not_connect_message": "اتصال شما به سوکت قطع شده است", "header": { "open_profile": "پروفایل", "edit_profile": " پروفایل", diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetButton.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetButton.jsx index 416e5c8..76af95c 100644 --- a/src/components/layouts/Dashboard/CallWidget/CallWidgetButton.jsx +++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetButton.jsx @@ -1,10 +1,12 @@ import PermPhoneMsgIcon from '@mui/icons-material/PermPhoneMsg'; import StyledFab from "@/core/components/StyledFab"; +import useCallDialog from "@/lib/callWidget/hooks/useCallDialog"; -const CallWidgetButton = ({setOpen}) => { +const CallWidgetButton = () => { + const {setOpenCallDialog} = useCallDialog() return ( setOpen(true)}> + onClick={() => setOpenCallDialog(true)}> ) 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 new file mode 100644 index 0000000..5b9326f --- /dev/null +++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions/index.jsx @@ -0,0 +1,7 @@ +const CallActions = ({tab}) => { + return ( + <>CallActions - {tab.id} + ) +} + +export default CallActions \ No newline at end of file diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/index.jsx new file mode 100644 index 0000000..292c640 --- /dev/null +++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory/index.jsx @@ -0,0 +1,7 @@ +const CallHistory = ({tab}) => { + return ( + <>CallHistory - {tab.id} + ) +} + +export default CallHistory \ No newline at end of file diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/index.jsx new file mode 100644 index 0000000..79dc736 --- /dev/null +++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/index.jsx @@ -0,0 +1,19 @@ +import {Grid} from "@mui/material"; +import CallActions from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallActions"; +import CallHistory from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel/CallHistory"; + +const CallTabPanel = ({tab}) => { + return ( + + + + + + + + + ) +} + +export default CallTabPanel \ No newline at end of file diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabLabel.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabLabel.jsx new file mode 100644 index 0000000..7a9b703 --- /dev/null +++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabLabel.jsx @@ -0,0 +1,23 @@ +import {IconButton, Stack, Typography, Zoom} from "@mui/material"; +import CloseIcon from '@mui/icons-material/Close'; +import useAnswers from "@/lib/callWidget/hooks/useAnswers"; + +const CallTabLabel = ({tab}) => { + const {closeAnswerTab} = useAnswers() + const handleCloseClick = (id) => { + closeAnswerTab(id) + }; + + return ( + + {tab.phone_number} - {tab.id} + + handleCloseClick(tab.id)}> + + + + + ) +} + +export default CallTabLabel \ No newline at end of file diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/index.jsx new file mode 100644 index 0000000..70fccd9 --- /dev/null +++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/index.jsx @@ -0,0 +1,27 @@ +import {Box, Tab, Tabs} from "@mui/material"; +import CallTabLabel + from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList/CallTabLabel"; +import useAnswers from "@/lib/callWidget/hooks/useAnswers"; + +const CallTabsList = () => { + const {answersList, changeActiveTabAnswers, activeTab} = useAnswers() + const handleChange = (event, newValue) => { + changeActiveTabAnswers(newValue) + }; + + return ( + + + {answersList.map((answer) => ( + } key={answer.id}/> + ))} + + + ) +} + +export default CallTabsList \ No newline at end of file diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/index.jsx new file mode 100644 index 0000000..4e1d2f1 --- /dev/null +++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/index.jsx @@ -0,0 +1,17 @@ +import CallTabsList from "src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabsList"; +import CallTabPanel from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs/CallTabPanel"; +import useAnswers from "@/lib/callWidget/hooks/useAnswers"; + +const CallTabs = () => { + const {answersList} = useAnswers() + + return ( + <> + + {answersList.map((answer) => ( + + ))} + + ) +} +export default CallTabs \ No newline at end of file diff --git a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/index.jsx b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/index.jsx index 77ed57d..5afb0a1 100644 --- a/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/index.jsx +++ b/src/components/layouts/Dashboard/CallWidget/CallWidgetDialog/index.jsx @@ -1,23 +1,47 @@ import {Dialog} from "@mui/material"; import {DialogTransition} from "@/core/components/DialogTransition"; +import {useEffect} from "react"; +import useCallDialog from "@/lib/callWidget/hooks/useCallDialog"; +import CallTabs from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog/CallTabs"; +import useAnswers from "@/lib/callWidget/hooks/useAnswers"; +import useSocket from "@/lib/app/hooks/useSocket"; -const CallWidgetDialog = ({open, setOpen}) => { +const CallWidgetDialog = () => { + const {openCallDialog, setOpenCallDialog} = useCallDialog() + const {answersList, newAnswerTab} = useAnswers() + const socket = useSocket() - const handleClose = () => { - setOpen(false); - }; + useEffect(() => { + const answerCall = (data, act) => { + newAnswerTab({ + id: data.id, + phone_number: data.phone_number + }) + act() + } + socket.on('answer', answerCall) + + return () => { + socket.off('answer', answerCall) + } + }, []); + + useEffect(() => { + if (answersList.length === 0) { + setOpenCallDialog(false) + return + } + setOpenCallDialog(true) + }, [answersList.length]); return ( - <> - - - - + + + ) } diff --git a/src/components/layouts/Dashboard/CallWidget/index.jsx b/src/components/layouts/Dashboard/CallWidget/index.jsx index 4d871b2..d6fe5a0 100644 --- a/src/components/layouts/Dashboard/CallWidget/index.jsx +++ b/src/components/layouts/Dashboard/CallWidget/index.jsx @@ -1,14 +1,27 @@ import CallWidgetButton from "@/components/layouts/Dashboard/CallWidget/CallWidgetButton"; import CallWidgetDialog from "@/components/layouts/Dashboard/CallWidget/CallWidgetDialog"; -import {useState} from "react"; +import {AnswersProvider} from "@/lib/callWidget/contexts/answers"; +import useSocket from "@/lib/app/hooks/useSocket"; +import {useEffect} from "react"; const CallWidget = () => { - const [open, setOpen] = useState(false) + const socket = useSocket() + + useEffect(() => { + if (socket.connected) return + + socket.connect() + + return () => { + socket.disconnect() + } + }, []); + return ( - <> - - - + + + + ) } diff --git a/src/core/components/StyledFab.jsx b/src/core/components/StyledFab.jsx index dd935cc..95c5ff7 100644 --- a/src/core/components/StyledFab.jsx +++ b/src/core/components/StyledFab.jsx @@ -5,7 +5,6 @@ const StyledFab = styled(Fab)` bottom: 16px; /* @noflip */ left: 16px; - z-index: 1500; `; export default StyledFab; diff --git a/src/lib/app/contexts/socket.jsx b/src/lib/app/contexts/socket.jsx index 7da4f43..47154c8 100644 --- a/src/lib/app/contexts/socket.jsx +++ b/src/lib/app/contexts/socket.jsx @@ -1,9 +1,18 @@ -import {createContext, useMemo} from "react"; +import {createContext, useEffect, useMemo, useRef, useState} from "react"; import {io} from "socket.io-client"; +import useUser from "@/lib/app/hooks/useUser"; +import {useTranslations} from "next-intl"; +import {toast} from "react-toastify"; +import PowerIcon from "@mui/icons-material/Power"; +import PowerOffIcon from "@mui/icons-material/PowerOff"; export const SocketContext = createContext() export const SocketProvider = ({children}) => { + const {user, isAuth} = useUser() + const [connectionError, setConnectionError] = useState(false) + const socketToastId = useRef(null); + const t = useTranslations() const socket = useMemo(() => io(process.env.NEXT_PUBLIC_SERVER_SOCKET_URL, { autoConnect: false, auth: { @@ -11,5 +20,48 @@ export const SocketProvider = ({children}) => { } }), []) + useEffect(() => { + if (isAuth) { + socket.auth.token = user.telephone_id + return + } + socket.auth.token = '' + }, [isAuth]); + + useEffect(() => { + const connectErrorHandler = () => { + setConnectionError(true) + } + const connectHandler = () => { + setConnectionError(false) + } + socket.on("connect_error", connectErrorHandler); + socket.on("connect", connectHandler); + + return () => { + socket.off("connect_error", connectErrorHandler); + socket.off("connect", connectHandler); + } + }, []); + + useEffect(() => { + if (!connectionError) { + toast.update(socketToastId.current, { + type: toast.TYPE.SUCCESS, + render: t('socket_is_connect_message'), + autoClose: 2000, + closeButton: true, + closeOnClick: true, + icon: + }); + return + } + socketToastId.current = toast.warn(t('socket_is_not_connect_message'), { + draggable: false, + autoClose: false, closeButton: false, closeOnClick: false, icon: + }) + + }, [connectionError]); + return {children} } \ No newline at end of file diff --git a/src/lib/callWidget/contexts/answers.jsx b/src/lib/callWidget/contexts/answers.jsx new file mode 100644 index 0000000..a9f7ae2 --- /dev/null +++ b/src/lib/callWidget/contexts/answers.jsx @@ -0,0 +1,31 @@ +import {createContext, useReducer, useState} from "react"; + +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 + }); + case "CHANGE_LIST": + return [...action.newList] + 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} +} diff --git a/src/lib/callWidget/hooks/useAnswers.jsx b/src/lib/callWidget/hooks/useAnswers.jsx new file mode 100644 index 0000000..2155cd7 --- /dev/null +++ b/src/lib/callWidget/hooks/useAnswers.jsx @@ -0,0 +1,38 @@ +import {useContext} from "react"; +import {AnswersContext} from "@/lib/callWidget/contexts/answers"; + +const useAnswers = () => { + const {state, dispatch, activeTab, setActiveTab} = useContext(AnswersContext) + + const changeActiveTabAnswers = (newValue) => { + dispatch({type: 'CHANGE_ACTIVE_TAB', newValue}) + setActiveTab(newValue) + } + + const newAnswerTab = (data) => { + const newAnswer = { + id: data.id, + phone_number: data.phone_number, + active: true + } + 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] + newList.splice(index, 1); + if (newList.length !== 0) { + newList[newIndex].active = true + setActiveTab(newIndex) + } + dispatch({type: 'CHANGE_LIST', newList}) + } + + return {answersList: state, activeTab, setActiveTab, changeActiveTabAnswers, closeAnswerTab, newAnswerTab} +} + +export default useAnswers \ No newline at end of file diff --git a/src/lib/callWidget/hooks/useCallDialog.jsx b/src/lib/callWidget/hooks/useCallDialog.jsx new file mode 100644 index 0000000..30dd599 --- /dev/null +++ b/src/lib/callWidget/hooks/useCallDialog.jsx @@ -0,0 +1,10 @@ +import {useContext} from "react"; +import {AnswersContext} from "@/lib/callWidget/contexts/answers"; + +const useCallDialog = () => { + const {openCallDialog, setOpenCallDialog} = useContext(AnswersContext) + + return {openCallDialog, setOpenCallDialog} +} + +export default useCallDialog \ No newline at end of file