diff --git a/package.json b/package.json index ed45b251..a047ed2f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@udecode/plate": "16.8", "@uiball/loaders": "^1.2.6", "bfj": "^7.0.2", + "broadcast-channel": "^4.20.2", "browserslist": "^4.21.4", "clsx": "^1.2.1", "copy-image-clipboard": "^2.1.2", diff --git a/src/common/component/InactiveScreen.tsx b/src/common/component/InactiveScreen.tsx new file mode 100644 index 00000000..b5ed28fd --- /dev/null +++ b/src/common/component/InactiveScreen.tsx @@ -0,0 +1,35 @@ +import { FC, useEffect } from "react"; +import useStreaming from "../hook/useStreaming"; +// import clsx from "clsx"; +import Button from "./styled/Button"; + +interface Props { +} + +const InactiveScreen: FC = () => { + const { stopStreaming } = useStreaming(); + // const [reloadVisible, setReloadVisible] = useState(false); + useEffect(() => { + stopStreaming(); + const currTitle = document.title; + document.title = `[INACTIVE] ${currTitle}`; + return () => { + document.title = currTitle; + }; + }, []); + const handleReload = () => { + location.reload(); + }; + return ( +
+
+

Only one active tab is allowed for VoceChat

+

Please reload this page to continue using this tab or close it

+ +
+ +
+ ); +}; + +export default InactiveScreen; diff --git a/src/common/hook/useStreaming/index.ts b/src/common/hook/useStreaming/index.ts index 541d92b6..49558fae 100644 --- a/src/common/hook/useStreaming/index.ts +++ b/src/common/hook/useStreaming/index.ts @@ -277,6 +277,8 @@ export default function useStreaming() { }, [afterMid, usersVersion]); const stopStreaming = () => { + // 先清掉定时器 + window.clearTimeout(aliveInter); if (SSE) { SSE.close(); SSE = undefined; diff --git a/src/common/hook/useTabBroadcast.ts b/src/common/hook/useTabBroadcast.ts new file mode 100644 index 00000000..e57e2e9c --- /dev/null +++ b/src/common/hook/useTabBroadcast.ts @@ -0,0 +1,33 @@ +import { useState, useEffect } from 'react'; +import { BroadcastChannel } from 'broadcast-channel'; +// import useStreaming from './useStreaming'; + +type ChannelData = { + type: "NEW_TAB", + message: string +} +const channel = new BroadcastChannel('VOCECHAT_CHANNEL'); +const useTabBroadcast = () => { + // const { stopStreaming } = useStreaming(); + const [tabActive, setTabActive] = useState(true); + useEffect(() => { + channel.postMessage({ type: "NEW_TAB", message: "new tab opened" } as ChannelData); + const handler = (data: ChannelData) => { + console.log("channel data", data); + if (data.type == "NEW_TAB") { + setTabActive(false); + } + }; + channel.addEventListener('message', handler); + return () => { + channel.removeEventListener("message", handler); + channel.close(); + }; + }, []); + + return { + tabActive + }; +}; + +export default useTabBroadcast; \ No newline at end of file diff --git a/src/routes/home/index.tsx b/src/routes/home/index.tsx index e2f6df1d..a6ae4239 100644 --- a/src/routes/home/index.tsx +++ b/src/routes/home/index.tsx @@ -1,5 +1,7 @@ import { memo } from "react"; import { Outlet, NavLink, useLocation, useMatch } from "react-router-dom"; +import { useTranslation } from "react-i18next"; + import StyledWrapper from "./styled"; import User from "./User"; // import Tools from "./Tools"; @@ -15,7 +17,6 @@ import UserIcon from "../../assets/icons/user.svg"; import FavIcon from "../../assets/icons/bookmark.svg"; import FolderIcon from "../../assets/icons/folder.svg"; import { useAppSelector } from "../../app/store"; -import { useTranslation } from "react-i18next"; // const routes = ["/setting", "/setting/channel/:cid"]; function HomePage() { const { t } = useTranslation(); diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 32bb1953..755872ae 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -3,6 +3,7 @@ import { Route, Routes, HashRouter } from "react-router-dom"; import { Provider } from "react-redux"; import toast from "react-hot-toast"; import { isEqual } from "lodash"; + import NotFoundPage from "./404"; // import Welcome from './Welcome' // const HomePage = lazy(() => import("./home")); @@ -28,14 +29,15 @@ const HomePage = lazy(() => import("./home")); import RequireAuth from "../common/component/RequireAuth"; import RequireNoAuth from "../common/component/RequireNoAuth"; import Meta from "../common/component/Meta"; -// import HomePage from "./home"; -// import ChatPage from "./chat"; import LazyIt from './lazy'; import store, { useAppSelector } from "../app/store"; import useDeviceToken from "../common/component/Notification/useDeviceToken"; import { vapidKey } from "../app/config"; +import useTabBroadcast from "../common/hook/useTabBroadcast"; +import InactiveScreen from "../common/component/InactiveScreen"; let toastId: string; const PageRoutes = () => { + const { ui: { online }, fileMessages @@ -198,6 +200,13 @@ const PageRoutes = () => { }; export default function ReduxRoutes() { + const { tabActive } = useTabBroadcast(); + if (!tabActive) return ( + + + + + ); return ( diff --git a/yarn.lock b/yarn.lock index df8b6b43..b6430c5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1102,6 +1102,13 @@ core-js-pure "^3.25.1" regenerator-runtime "^0.13.11" +"@babel/runtime@7.20.7": + version "7.20.7" + resolved "https://mirrors.cloud.tencent.com/npm/@babel%2fruntime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd" + integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ== + dependencies: + regenerator-runtime "^0.13.11" + "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.9", "@babel/runtime@^7.19.4", "@babel/runtime@^7.20.6", "@babel/runtime@^7.3.1", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.20.6" resolved "https://mirrors.cloud.tencent.com/npm/@babel%2fruntime/-/runtime-7.20.6.tgz#facf4879bfed9b5326326273a64220f099b0fce3" @@ -4762,6 +4769,17 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" +broadcast-channel@^4.20.2: + version "4.20.2" + resolved "https://mirrors.cloud.tencent.com/npm/broadcast-channel/-/broadcast-channel-4.20.2.tgz#34c639251dfc586da7c8c1d6b2418dafa9568ae0" + integrity sha512-v0lJgMzC+MX4e2KCFWYXChZ2mKTqm5mnJGId6tqJp3NfylggbNd8c2uKeP4MQxD2ucKOesY68aN98zwl9d6Tvg== + dependencies: + "@babel/runtime" "7.20.7" + oblivious-set "1.1.1" + p-queue "6.6.2" + rimraf "3.0.2" + unload "2.4.1" + browser-process-hrtime@^1.0.0: version "1.0.0" resolved "https://mirrors.cloud.tencent.com/npm/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" @@ -6461,7 +6479,7 @@ ev-emitter@^1.0.0: resolved "https://mirrors.cloud.tencent.com/npm/ev-emitter/-/ev-emitter-1.1.1.tgz#8f18b0ce5c76a5d18017f71c0a795c65b9138f2a" integrity sha512-ipiDYhdQSCZ4hSbX4rMW+XzNKMD1prg/sTvoVmSLkuQ1MVlwjJQQA+sW8tMYR3BLUr9KjodFV4pvzunvRhd33Q== -eventemitter3@^4.0.0: +eventemitter3@^4.0.0, eventemitter3@^4.0.4: version "4.0.7" resolved "https://mirrors.cloud.tencent.com/npm/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -9246,6 +9264,11 @@ object.values@^1.1.0, object.values@^1.1.5, object.values@^1.1.6: define-properties "^1.1.4" es-abstract "^1.20.4" +oblivious-set@1.1.1: + version "1.1.1" + resolved "https://mirrors.cloud.tencent.com/npm/oblivious-set/-/oblivious-set-1.1.1.tgz#d9d38e9491d51f27a5c3ec1681d2ba40aa81e98b" + integrity sha512-Oh+8fK09mgGmAshFdH6hSVco6KZmd1tTwNFWj35OvzdmJTMZtAkbn05zar2iG3v6sDs1JLEtOiBGNb6BHwkb2w== + obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://mirrors.cloud.tencent.com/npm/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -9344,6 +9367,11 @@ outlayer@^2.1.0: fizzy-ui-utils "^2.0.0" get-size "^2.0.2" +p-finally@^1.0.0: + version "1.0.0" + resolved "https://mirrors.cloud.tencent.com/npm/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://mirrors.cloud.tencent.com/npm/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -9386,6 +9414,14 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" +p-queue@6.6.2: + version "6.6.2" + resolved "https://mirrors.cloud.tencent.com/npm/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" + integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== + dependencies: + eventemitter3 "^4.0.4" + p-timeout "^3.2.0" + p-retry@^4.5.0: version "4.6.2" resolved "https://mirrors.cloud.tencent.com/npm/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" @@ -9394,6 +9430,13 @@ p-retry@^4.5.0: "@types/retry" "0.12.0" retry "^0.13.1" +p-timeout@^3.2.0: + version "3.2.0" + resolved "https://mirrors.cloud.tencent.com/npm/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== + dependencies: + p-finally "^1.0.0" + p-try@^2.0.0: version "2.2.0" resolved "https://mirrors.cloud.tencent.com/npm/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -11049,6 +11092,13 @@ rfdc@^1.3.0: resolved "https://mirrors.cloud.tencent.com/npm/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== +rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://mirrors.cloud.tencent.com/npm/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rimraf@^2.6.3: version "2.7.1" resolved "https://mirrors.cloud.tencent.com/npm/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -11056,13 +11106,6 @@ rimraf@^2.6.3: dependencies: glob "^7.1.3" -rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://mirrors.cloud.tencent.com/npm/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rollup-plugin-terser@^7.0.0: version "7.0.2" resolved "https://mirrors.cloud.tencent.com/npm/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" @@ -12334,6 +12377,11 @@ universalify@^2.0.0: resolved "https://mirrors.cloud.tencent.com/npm/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== +unload@2.4.1: + version "2.4.1" + resolved "https://mirrors.cloud.tencent.com/npm/unload/-/unload-2.4.1.tgz#b0c5b7fb44e17fcbf50dcb8fb53929c59dd226a5" + integrity sha512-IViSAm8Z3sRBYA+9wc0fLQmU9Nrxb16rcDmIiR6Y9LJSZzI7QY5QsDhqPpKOjAn0O9/kfK1TfNEMMAGPTIraPw== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://mirrors.cloud.tencent.com/npm/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"