diff --git a/package.json b/package.json index c40fa32ffb..36f523d214 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,8 @@ "react-focus-lock": "2.13.2", "react-i18next": "^15.1.3", "react-is": "18.3.1", + "react-router": "6.30.0", + "react-router-dom": "6.30.0", "spatial-navigation-polyfill": "github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6", "stremio-translations": "github:Stremio/stremio-translations#176c69f3bdede824f37979a046ee27cef355affc", "url": "0.11.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b9107a424..fa710ee66f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -86,6 +86,12 @@ importers: react-is: specifier: 18.3.1 version: 18.3.1 + react-router: + specifier: 6.30.0 + version: 6.30.0(react@18.3.1) + react-router-dom: + specifier: 6.30.0 + version: 6.30.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) spatial-navigation-polyfill: specifier: github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6 version: https://codeload.github.com/Stremio/spatial-navigation/tar.gz/64871b1422466f5f45d24ebc8bbd315b2ebab6a6 @@ -1031,6 +1037,10 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@remix-run/router@1.23.0': + resolution: {integrity: sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==} + engines: {node: '>=14.0.0'} + '@rollup/plugin-babel@5.3.1': resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} engines: {node: '>= 10.0.0'} @@ -3811,6 +3821,19 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-router-dom@6.30.0: + resolution: {integrity: sha512-x30B78HV5tFk8ex0ITwzC9TTZMua4jGyA9IUlH1JLQYQTFyxr/ZxwOJq7evg1JX1qGVUcvhsmQSKdPncQrjTgA==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + react-router@6.30.0: + resolution: {integrity: sha512-D3X8FyH9nBcTSHGdEKurK7r8OYE1kKFn3d/CF+CoxbSHkxU7o37+Uh7eAHRXr6k2tSExXYO++07PeXJtA/dEhQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -5778,6 +5801,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 + '@remix-run/router@1.23.0': {} + '@rollup/plugin-babel@5.3.1(@babel/core@7.26.0)(@types/babel__core@7.20.5)(rollup@2.79.2)': dependencies: '@babel/core': 7.26.0 @@ -8996,6 +9021,18 @@ snapshots: react-is@18.3.1: {} + react-router-dom@6.30.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@remix-run/router': 1.23.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-router: 6.30.0(react@18.3.1) + + react-router@6.30.0(react@18.3.1): + dependencies: + '@remix-run/router': 1.23.0 + react: 18.3.1 + react@18.3.1: dependencies: loose-envify: 1.4.0 diff --git a/src/App/App.js b/src/App/App.js index eecca48ea8..53d80145b5 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -5,28 +5,21 @@ const React = require('react'); const { useTranslation } = require('react-i18next'); const { Router } = require('stremio-router'); const { Core, Shell, Chromecast, DragAndDrop, KeyboardShortcuts, ServicesProvider, GamepadProvider } = require('stremio/services'); -const { NotFound } = require('stremio/routes'); const { FileDropProvider, PlatformProvider, ToastProvider, TooltipProvider, ShortcutsProvider, CONSTANTS, withCoreSuspender, useShell, useBinaryState } = require('stremio/common'); const ServicesToaster = require('./ServicesToaster'); -const DeepLinkHandler = require('./DeepLinkHandler'); const SearchParamsHandler = require('./SearchParamsHandler'); const { default: UpdaterBanner } = require('./UpdaterBanner'); const { default: ShortcutsModal } = require('./ShortcutsModal'); const { default: GamepadModal } = require('./GamepadModal'); const ErrorDialog = require('./ErrorDialog'); -const withProtectedRoutes = require('./withProtectedRoutes'); -const routerViewsConfig = require('./routerViewsConfig'); const styles = require('./styles'); -const RouterWithProtectedRoutes = withCoreSuspender(withProtectedRoutes(Router)); +const RouterWithProtectedRoutes = withCoreSuspender(Router); const App = () => { const { i18n } = useTranslation(); const shell = useShell(); const [gamepadSupportEnabled, setGamepadSupportEnabled] = React.useState(false); - const onPathNotMatch = React.useCallback(() => { - return NotFound; - }, []); const services = React.useMemo(() => { const core = new Core({ appVersion: process.env.VERSION, @@ -116,31 +109,6 @@ const App = () => { }; }, []); - // Handle shell events - React.useEffect(() => { - const onOpenMedia = (data) => { - try { - const { protocol, hostname, pathname, searchParams } = new URL(data); - if (protocol === CONSTANTS.PROTOCOL) { - if (hostname.length) { - const transportUrl = `https://${hostname}${pathname}`; - window.location.href = `#/addons?addon=${encodeURIComponent(transportUrl)}`; - } else { - window.location.href = `#${pathname}?${searchParams.toString()}`; - } - } - } catch (e) { - console.error('Failed to open media:', e); - } - }; - - shell.on('open-media', onOpenMedia); - - return () => { - shell.off('open-media', onOpenMedia); - }; - }, []); - React.useEffect(() => { const onCoreEvent = ({ event, args }) => { switch (event) { @@ -238,13 +206,10 @@ const App = () => { gamepadModalOpen && } - diff --git a/src/App/DeepLinkHandler.js b/src/App/DeepLinkHandler.js index 2df2a2e43e..910ba75946 100644 --- a/src/App/DeepLinkHandler.js +++ b/src/App/DeepLinkHandler.js @@ -1,9 +1,12 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); +const { useNavigate } = require('react-router'); const { withCoreSuspender, useStreamingServer } = require('stremio/common'); +const { default: toPath } = require('stremio/common/toPath'); const DeepLinkHandler = () => { + const navigate = useNavigate(); const streamingServer = useStreamingServer(); React.useEffect(() => { if (streamingServer.torrent !== null) { @@ -11,7 +14,7 @@ const DeepLinkHandler = () => { if (type === 'Ready') { const [, deepLinks] = content; if (typeof deepLinks.metaDetailsVideos === 'string') { - window.location = deepLinks.metaDetailsVideos; + navigate(toPath(deepLinks.metaDetailsVideos)); } } } diff --git a/src/App/OpenMediaHandler.tsx b/src/App/OpenMediaHandler.tsx new file mode 100644 index 0000000000..1898c535db --- /dev/null +++ b/src/App/OpenMediaHandler.tsx @@ -0,0 +1,35 @@ +// Copyright (C) 2017-2026 Smart code 203358507 + +import { useEffect } from 'react'; +import { useNavigate } from 'react-router'; +import { useShell, CONSTANTS } from 'stremio/common'; + +const OpenMediaHandler = () => { + const navigate = useNavigate(); + const shell = useShell(); + + useEffect(() => { + const onOpenMedia = (data: string) => { + try { + const { protocol, hostname, pathname, searchParams } = new URL(data); + if (protocol === CONSTANTS.PROTOCOL) { + if (hostname.length) { + const transportUrl = `https://${hostname}${pathname}`; + navigate(`/addons?addon=${encodeURIComponent(transportUrl)}`); + } else { + navigate(`${pathname}?${searchParams.toString()}`); + } + } + } catch (e) { + console.error('Failed to open media:', e); + } + }; + + shell.on('open-media', onOpenMedia); + return () => shell.off('open-media', onOpenMedia); + }, [navigate, shell]); + + return null; +}; + +export default OpenMediaHandler; diff --git a/src/App/withProtectedRoutes.js b/src/App/withProtectedRoutes.js deleted file mode 100644 index a16e0c0c78..0000000000 --- a/src/App/withProtectedRoutes.js +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const React = require('react'); -const { Intro } = require('stremio/routes'); -const { useProfile } = require('stremio/common'); - -const withProtectedRoutes = (Component) => { - return function withProtectedRoutes(props) { - const profile = useProfile(); - const previousAuthRef = React.useRef(profile.auth); - React.useEffect(() => { - if (previousAuthRef.current !== null && profile.auth === null) { - window.location = '#/intro'; - } - previousAuthRef.current = profile.auth; - }, [profile]); - const onRouteChange = React.useCallback((routeConfig) => { - if (profile.auth !== null && routeConfig.component === Intro) { - window.location.replace('#/'); - return true; - } - }, [profile]); - return ( - - ); - }; -}; - -module.exports = withProtectedRoutes; diff --git a/src/common/index.js b/src/common/index.js index e608e7e23a..c5cb581d96 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -21,6 +21,7 @@ const useModelState = require('./useModelState'); const useNotifications = require('./useNotifications'); const useOnScrollToBottom = require('./useOnScrollToBottom'); const useProfile = require('./useProfile'); +const { default: useRouteFocused } = require('./useRouteFocused'); const { default: useSettings } = require('./useSettings'); const { default: useShell } = require('./useShell'); const useStreamingServer = require('./useStreamingServer'); @@ -60,6 +61,7 @@ module.exports = { useNotifications, useOnScrollToBottom, useProfile, + useRouteFocused, useSettings, useShell, useStreamingServer, diff --git a/src/common/routerPaths.tsx b/src/common/routerPaths.tsx new file mode 100644 index 0000000000..9cd98a9ecd --- /dev/null +++ b/src/common/routerPaths.tsx @@ -0,0 +1,59 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +import React from 'react'; +import routes from 'stremio/routes'; + +export const routerPaths = [ + { + path: '/intro', + element: , + }, + { + path: '/discover/:transportUrl?/:type?/:catalogId?', + element: , + }, + { + path: '/library/:type?', + element: , + }, + { + path: '/calendar/:year?/:month?', + element: , + }, + { + path: '/continuewatching/:type?', + element: , + }, + { + path: '/search', + element: , + }, + { + path: '/metadetails/:type?/:id?/:videoId?', + element: , + }, + { + path: '/detail/:type?/:id?/:videoId?', + element: , + }, + { + path: '/addons/:type?/:transportUrl?/:catalogId?', + element: , + }, + { + path: '/settings', + element: , + }, + { + path: '/player/:stream?/:streamTransportUrl?/:metaTransportUrl?/:type?/:id?/:videoId?', + element: , + }, + { + path: '/', + element: , + }, + { + path: '*', + element: , + }, +]; diff --git a/src/common/toPath.ts b/src/common/toPath.ts new file mode 100644 index 0000000000..62021c975c --- /dev/null +++ b/src/common/toPath.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2026 Smart code 203358507 + +const toPath = (link: string): string => link.startsWith('#') ? link.slice(1) : link; + +export default toPath; diff --git a/src/common/useModelState.js b/src/common/useModelState.js index da637b8ff2..081ad20721 100644 --- a/src/common/useModelState.js +++ b/src/common/useModelState.js @@ -5,7 +5,7 @@ const throttle = require('lodash.throttle'); const { deepEqual } = require('fast-equals'); const intersection = require('lodash.intersection'); const { useCoreSuspender } = require('stremio/common/CoreSuspender'); -const { useRouteFocused } = require('stremio-router'); +const { default: useRouteFocused } = require('stremio/common/useRouteFocused'); const { useServices } = require('stremio/services'); const useModelState = ({ action, ...args }) => { diff --git a/src/common/useNavigateWithOrigin.ts b/src/common/useNavigateWithOrigin.ts new file mode 100644 index 0000000000..2e5fa90004 --- /dev/null +++ b/src/common/useNavigateWithOrigin.ts @@ -0,0 +1,39 @@ +import { useLocation, useNavigate, To, Location } from 'react-router-dom'; + +const ORIGIN_KEY = 'originPath'; + +export function useNavigateWithOrigin() { + const navigate = useNavigate(); + const location = useLocation(); + + function navigateWithOrigin(target: To) { + const origin: Location = location.state?.from || location; + + // Save origin in sessionStorage + sessionStorage.setItem(ORIGIN_KEY, origin.pathname + origin.search); + + // Navigate and propagate origin + navigate(target, { + state: { from: origin }, + }); + } + + function setOriginPath(path?: string) { + const finalPath = path ?? location.pathname + location.search; + sessionStorage.setItem(ORIGIN_KEY, finalPath); + } + + function getStoredOrigin(fallback = '/'): string { + if (location.state?.from) { + const from = location.state.from as Location; + return from.pathname + (from.search || ''); + } + return sessionStorage.getItem(ORIGIN_KEY) || fallback; + } + + return { + navigateWithOrigin, + getStoredOrigin, + setOriginPath, + }; +} diff --git a/src/common/usePlayUrl.ts b/src/common/usePlayUrl.ts index 49fe386ed2..9f79037eb1 100644 --- a/src/common/usePlayUrl.ts +++ b/src/common/usePlayUrl.ts @@ -1,4 +1,5 @@ import { useCallback } from 'react'; +import { useNavigate } from 'react-router'; import magnet from 'magnet-uri'; import { useServices } from 'stremio/services'; import useToast from 'stremio/common/Toast/useToast'; @@ -8,6 +9,7 @@ import useStreamingServer from 'stremio/common/useStreamingServer'; const HTTP_REGEX = /^https?:\/\/.+/i; const usePlayUrl = () => { + const navigate = useNavigate(); const { core } = useServices(); const toast = useToast(); const { createTorrentFromMagnet } = useTorrent(); @@ -26,7 +28,7 @@ const usePlayUrl = () => { try { const encoded = await core.transport.encodeStream({ url: trimmed }); if (typeof encoded === 'string') { - window.location.hash = `#/player/${encodeURIComponent(encoded)}`; + navigate(`/player/${encodeURIComponent(encoded)}`); return true; } } catch (e) { diff --git a/src/common/useRouteFocused.ts b/src/common/useRouteFocused.ts new file mode 100644 index 0000000000..80037f7d36 --- /dev/null +++ b/src/common/useRouteFocused.ts @@ -0,0 +1,24 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +import React from 'react'; + +const useRouteFocused = () => { + const [isFocused, setIsFocused] = React.useState(document.hasFocus()); + + React.useEffect(() => { + const handleFocus = () => setIsFocused(true); + const handleBlur = () => setIsFocused(false); + + window.addEventListener('focus', handleFocus); + window.addEventListener('blur', handleBlur); + + return () => { + window.removeEventListener('focus', handleFocus); + window.removeEventListener('blur', handleBlur); + }; + }, []); + + return isFocused; +}; + +export default useRouteFocused; diff --git a/src/components/LibItem/LibItem.js b/src/components/LibItem/LibItem.js index 28769ddcf1..21c78fcf3f 100644 --- a/src/components/LibItem/LibItem.js +++ b/src/components/LibItem/LibItem.js @@ -1,14 +1,16 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); +const { useNavigate } = require('react-router'); +const { default: toPath } = require('stremio/common/toPath'); const { useServices } = require('stremio/services'); const PropTypes = require('prop-types'); const MetaItem = require('stremio/components/MetaItem'); const { t } = require('i18next'); const LibItem = ({ _id, removable, notifications, watched, ...props }) => { - const { core } = useServices(); + const navigate = useNavigate(); const newVideos = React.useMemo(() => { const count = notifications.items?.[_id]?.length ?? 0; @@ -50,7 +52,7 @@ const LibItem = ({ _id, removable, notifications, watched, ...props }) => { switch (event.value) { case 'play': { if (props.deepLinks && typeof props.deepLinks.player === 'string') { - window.location = props.deepLinks.player; + navigate(toPath(props.deepLinks.player)); } break; @@ -58,9 +60,9 @@ const LibItem = ({ _id, removable, notifications, watched, ...props }) => { case 'details': { if (props.deepLinks) { if (typeof props.deepLinks.metaDetailsVideos === 'string') { - window.location = props.deepLinks.metaDetailsVideos; + navigate(toPath(props.deepLinks.metaDetailsVideos)); } else if (typeof props.deepLinks.metaDetailsStreams === 'string') { - window.location = props.deepLinks.metaDetailsStreams; + navigate(toPath(props.deepLinks.metaDetailsStreams)); } } @@ -123,7 +125,7 @@ const LibItem = ({ _id, removable, notifications, watched, ...props }) => { if (props.deepLinks && typeof props.deepLinks.player === 'string') { return (event) => { event.preventDefault(); - window.location = props.deepLinks.player; + navigate(toPath(props.deepLinks.player)); }; } return null; diff --git a/src/components/MainNavBars/MainNavBars.tsx b/src/components/MainNavBars/MainNavBars.tsx index 1dae27a16b..1b8037eb55 100644 --- a/src/components/MainNavBars/MainNavBars.tsx +++ b/src/components/MainNavBars/MainNavBars.tsx @@ -7,12 +7,12 @@ import { useContentGamepadNavigation, useVerticalNavGamepadNavigation } from 'st import styles from './MainNavBars.less'; const TABS = [ - { id: 'board', label: 'Board', icon: 'home', href: '#/' }, - { id: 'discover', label: 'Discover', icon: 'discover', href: '#/discover' }, - { id: 'library', label: 'Library', icon: 'library', href: '#/library' }, - { id: 'calendar', label: 'Calendar', icon: 'calendar', href: '#/calendar' }, - { id: 'addons', label: 'ADDONS', icon: 'addons', href: '#/addons' }, - { id: 'settings', label: 'SETTINGS', icon: 'settings', href: '#/settings' }, + { id: 'board', label: 'Board', icon: 'home', href: '/' }, + { id: 'discover', label: 'Discover', icon: 'discover', href: '/discover' }, + { id: 'library', label: 'Library', icon: 'library', href: '/library' }, + { id: 'calendar', label: 'Calendar', icon: 'calendar', href: '/calendar' }, + { id: 'addons', label: 'ADDONS', icon: 'addons', href: '/addons' }, + { id: 'settings', label: 'SETTINGS', icon: 'settings', href: '/settings' }, ]; type Props = { diff --git a/src/components/MetaItem/MetaItem.js b/src/components/MetaItem/MetaItem.js index 0e66c6a9ee..bd61ef9641 100644 --- a/src/components/MetaItem/MetaItem.js +++ b/src/components/MetaItem/MetaItem.js @@ -6,6 +6,7 @@ const classnames = require('classnames'); const { useTranslation } = require('react-i18next'); const filterInvalidDOMProps = require('filter-invalid-dom-props').default; const { default: Icon } = require('@stremio/stremio-icons/react'); +const { useNavigateWithOrigin } = require('stremio/common/useNavigateWithOrigin'); const { default: Button } = require('stremio/components/Button'); const { default: Image } = require('stremio/components/Image'); const Multiselect = require('stremio/components/Multiselect'); @@ -15,6 +16,7 @@ const styles = require('./styles'); const MetaItem = React.memo(({ className, type, name, poster, posterShape, posterChangeCursor, progress, newVideos, options, deepLinks, dataset, optionOnSelect, onDismissClick, onPlayClick, watched, ...props }) => { const { t } = useTranslation(); + const { setOriginPath } = useNavigateWithOrigin(); const [menuOpen, onMenuOpen, onMenuClose] = useBinaryState(false); const href = React.useMemo(() => { return deepLinks ? @@ -32,6 +34,7 @@ const MetaItem = React.memo(({ className, type, name, poster, posterShape, poste null; }, [deepLinks]); const metaItemOnClick = React.useCallback((event) => { + setOriginPath(); if (event.nativeEvent.selectPrevented) { event.preventDefault(); } else if (typeof props.onClick === 'function') { diff --git a/src/components/ModalDialog/ModalDialog.js b/src/components/ModalDialog/ModalDialog.js index b07481f695..44f1f1fdb7 100644 --- a/src/components/ModalDialog/ModalDialog.js +++ b/src/components/ModalDialog/ModalDialog.js @@ -4,10 +4,11 @@ const React = require('react'); const { useTranslation } = require('react-i18next'); const PropTypes = require('prop-types'); const classnames = require('classnames'); -const { useRouteFocused, useModalsContainer } = require('stremio-router'); +const { useModalsContainer } = require('stremio/router/ModalsContainerContext'); +const Modal = require('stremio/router/Modal'); +const { default: useRouteFocused } = require('stremio/common/useRouteFocused'); const { default: Button } = require('stremio/components/Button'); const { default: Icon } = require('@stremio/stremio-icons/react'); -const { Modal } = require('stremio-router'); const styles = require('./styles'); const ModalDialog = ({ className, title, buttons, children, dataset, onCloseRequest, background, ...props }) => { diff --git a/src/components/NavBar/HorizontalNavBar/HorizontalNavBar.js b/src/components/NavBar/HorizontalNavBar/HorizontalNavBar.js index c6c02ab46c..97e20642fa 100644 --- a/src/components/NavBar/HorizontalNavBar/HorizontalNavBar.js +++ b/src/components/NavBar/HorizontalNavBar/HorizontalNavBar.js @@ -1,6 +1,7 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); +const { useNavigate } = require('react-router'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { default: Icon } = require('@stremio/stremio-icons/react'); @@ -13,10 +14,15 @@ const NavMenu = require('./NavMenu'); const styles = require('./styles'); const { t } = require('i18next'); -const HorizontalNavBar = React.memo(({ className, route, query, title, backButton, searchBar, fullscreenButton, navMenu, hdrInfo, ...props }) => { +const HorizontalNavBar = React.memo(({ className, route, query, title, backButton, searchBar, fullscreenButton, navMenu, originPath, hdrInfo, ...props }) => { + const navigate = useNavigate(); const backButtonOnClick = React.useCallback(() => { - window.history.back(); - }, []); + if (originPath) { + navigate(originPath); + } else { + navigate(-1); + } + }, [originPath, navigate]); const [fullscreen, requestFullscreen, exitFullscreen] = useFullscreen(); const [isIOSPWA] = usePWA(); const renderNavMenuLabel = React.useCallback(({ ref, className, onClick, children, }) => ( @@ -93,6 +99,7 @@ HorizontalNavBar.propTypes = { searchBar: PropTypes.bool, fullscreenButton: PropTypes.bool, navMenu: PropTypes.bool, + originPath: PropTypes.string, hdrInfo: PropTypes.shape({ gamma: PropTypes.string, }), diff --git a/src/components/NavBar/HorizontalNavBar/NavMenu/NavMenu.js b/src/components/NavBar/HorizontalNavBar/NavMenu/NavMenu.js index 8d381f3caf..b5de0ee710 100644 --- a/src/components/NavBar/HorizontalNavBar/NavMenu/NavMenu.js +++ b/src/components/NavBar/HorizontalNavBar/NavMenu/NavMenu.js @@ -3,7 +3,7 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); -const { useRouteFocused } = require('stremio-router'); +const { default: useRouteFocused } = require('stremio/common/useRouteFocused'); const Popup = require('stremio/components/Popup'); const useBinaryState = require('stremio/common/useBinaryState'); const NavMenuContent = require('./NavMenuContent'); diff --git a/src/components/NavBar/HorizontalNavBar/NavMenu/NavMenuContent.js b/src/components/NavBar/HorizontalNavBar/NavMenu/NavMenuContent.js index b6309a44cb..8a915b04ad 100644 --- a/src/components/NavBar/HorizontalNavBar/NavMenu/NavMenuContent.js +++ b/src/components/NavBar/HorizontalNavBar/NavMenu/NavMenuContent.js @@ -1,6 +1,7 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); +const { useNavigate } = require('react-router'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { useTranslation } = require('react-i18next'); @@ -18,6 +19,7 @@ const styles = require('./styles'); const NavMenuContent = ({ onClick }) => { const { t } = useTranslation(); + const navigate = useNavigate(); const { core } = useServices(); const profile = useProfile(); const streamingServer = useStreamingServer(); @@ -54,6 +56,12 @@ const NavMenuContent = ({ onClick }) => { console.error(e); } }, [handlePlayUrl]); + const handleAuth = React.useCallback(() => { + return profile.auth !== null + ? logoutButtonOnClick() + : navigate('/intro'); + }, [profile.auth, logoutButtonOnClick, navigate]); + return (
@@ -73,7 +81,7 @@ const NavMenuContent = ({ onClick }) => {
{profile.auth === null ? t('ANONYMOUS_USER') : profile.auth.user.email}
-
diff --git a/src/components/NavBar/HorizontalNavBar/SearchBar/SearchBar.js b/src/components/NavBar/HorizontalNavBar/SearchBar/SearchBar.js index e8f58bdff3..7ce785213e 100644 --- a/src/components/NavBar/HorizontalNavBar/SearchBar/SearchBar.js +++ b/src/components/NavBar/HorizontalNavBar/SearchBar/SearchBar.js @@ -1,12 +1,14 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); +const { useNavigate } = require('react-router'); +const { useSearchParams } = require('react-router-dom'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const debounce = require('lodash.debounce'); const { useTranslation } = require('react-i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); -const { useRouteFocused } = require('stremio-router'); +const { default: useRouteFocused } = require('stremio/common/useRouteFocused'); const Button = require('stremio/components/Button').default; const TextInput = require('stremio/components/TextInput').default; const { default: usePlayUrl } = require('stremio/common/usePlayUrl'); @@ -21,17 +23,18 @@ const SearchBar = React.memo(({ className, query, active }) => { const routeFocused = useRouteFocused(); const searchHistory = useSearchHistory(); const localSearch = useLocalSearch(); + const navigate = useNavigate(); const { handlePlayUrl } = usePlayUrl(); const [historyOpen, openHistory, closeHistory, ] = useBinaryState(query === null ? true : false); const [currentQuery, setCurrentQuery] = React.useState(query || ''); - + const [, setSearchParams] = useSearchParams(); const searchInputRef = React.useRef(null); const containerRef = React.useRef(null); const searchBarOnClick = React.useCallback(() => { if (!active) { - window.location = '#/search'; + navigate('/search'); } }, [active]); @@ -66,7 +69,7 @@ const SearchBar = React.memo(({ className, query, active }) => { const searchValue = `/search?search=${encodeURIComponent(event.target.value)}`; setCurrentQuery(searchValue); if (searchInputRef.current && searchValue) { - window.location.hash = searchValue; + setSearchParams({ search: event.target.value }); closeHistory(); } }, []); @@ -74,7 +77,8 @@ const SearchBar = React.memo(({ className, query, active }) => { const queryInputClear = React.useCallback(() => { searchInputRef.current.value = ''; setCurrentQuery(''); - window.location.hash = '/search'; + setSearchParams({}); + navigate('/search'); }, []); const updateLocalSearchDebounced = React.useCallback(debounce((query) => { diff --git a/src/components/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js b/src/components/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js index 65c6a02a91..e59f106f75 100644 --- a/src/components/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js +++ b/src/components/NavBar/VerticalNavBar/NavTabButton/NavTabButton.js @@ -4,8 +4,9 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const { default: Icon } = require('@stremio/stremio-icons/react'); -const { Button, Image } = require('stremio/components'); +const { Image } = require('stremio/components'); const styles = require('./styles'); +const { Link } = require('react-router-dom'); const NavTabButton = ({ className, logo, icon, label, href, selected, onClick }) => { const renderLogoFallback = React.useCallback(() => ( @@ -24,7 +25,7 @@ const NavTabButton = ({ className, logo, icon, label, href, selected, onClick }) }); }; return ( -