diff --git a/package-lock.json b/package-lock.json index 7d5ed4487..0ad583043 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,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#abe7684165a031755e9aee39da26daa806ba7824", "url": "0.11.4", @@ -3105,6 +3107,15 @@ "node": ">= 8" } }, + "node_modules/@remix-run/router": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", + "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -12498,6 +12509,38 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "license": "MIT" }, + "node_modules/react-router": { + "version": "6.30.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.0.tgz", + "integrity": "sha512-D3X8FyH9nBcTSHGdEKurK7r8OYE1kKFn3d/CF+CoxbSHkxU7o37+Uh7eAHRXr6k2tSExXYO++07PeXJtA/dEhQ==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.0.tgz", + "integrity": "sha512-x30B78HV5tFk8ex0ITwzC9TTZMua4jGyA9IUlH1JLQYQTFyxr/ZxwOJq7evg1JX1qGVUcvhsmQSKdPncQrjTgA==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.0", + "react-router": "6.30.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/readable-stream": { "version": "3.6.0", "dev": true, diff --git a/package.json b/package.json index ffcaef6b2..a31285d10 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#abe7684165a031755e9aee39da26daa806ba7824", "url": "0.11.4", diff --git a/src/App/App.js b/src/App/App.js index 3e816be9f..a1976b586 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -5,25 +5,19 @@ const React = require('react'); const { useTranslation } = require('react-i18next'); const { Router } = require('stremio-router'); const { Core, Shell, Chromecast, DragAndDrop, KeyboardShortcuts, ServicesProvider } = require('stremio/services'); -const { NotFound } = require('stremio/routes'); const { FileDropProvider, PlatformProvider, ToastProvider, TooltipProvider, CONSTANTS, withCoreSuspender, useShell } = require('stremio/common'); const ServicesToaster = require('./ServicesToaster'); const DeepLinkHandler = require('./DeepLinkHandler'); const SearchParamsHandler = require('./SearchParamsHandler'); const { default: UpdaterBanner } = require('./UpdaterBanner'); 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 onPathNotMatch = React.useCallback(() => { - return NotFound; - }, []); const services = React.useMemo(() => { const core = new Core({ appVersion: process.env.VERSION, @@ -207,11 +201,7 @@ const App = () => { - + diff --git a/src/App/withProtectedRoutes.js b/src/App/withProtectedRoutes.js deleted file mode 100644 index a16e0c0c7..000000000 --- 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 25df5c158..0200e1b17 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'); @@ -57,6 +58,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 000000000..9cd98a9ec --- /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/useModelState.js b/src/common/useModelState.js index 42672dc22..8f22f2a02 100644 --- a/src/common/useModelState.js +++ b/src/common/useModelState.js @@ -5,7 +5,7 @@ const throttle = require('lodash.throttle'); const isEqual = require('lodash.isequal'); 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 }) => { @@ -32,17 +32,17 @@ const useModelState = ({ action, ...args }) => { } } ); - React.useInsertionEffect(() => { + React.useLayoutEffect(() => { if (action) { core.transport.dispatch(action, model); } }, [action]); - React.useInsertionEffect(() => { + React.useLayoutEffect(() => { return () => { core.transport.dispatch({ action: 'Unload' }, model); }; }, []); - React.useInsertionEffect(() => { + React.useLayoutEffect(() => { const onNewState = async (models) => { if (models.indexOf(model) === -1 && (!Array.isArray(deps) || intersection(deps, models).length === 0)) { return; @@ -67,7 +67,7 @@ const useModelState = ({ action, ...args }) => { core.transport.off('NewState', onNewStateThrottled); }; }, [routeFocused]); - React.useInsertionEffect(() => { + React.useLayoutEffect(() => { mountedRef.current = true; }, []); return state; diff --git a/src/common/useNavigateWithOrigin.ts b/src/common/useNavigateWithOrigin.ts new file mode 100644 index 000000000..51c58a8da --- /dev/null +++ b/src/common/useNavigateWithOrigin.ts @@ -0,0 +1,35 @@ +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 { + return sessionStorage.getItem(ORIGIN_KEY) || fallback; + } + + return { + navigateWithOrigin, + getStoredOrigin, + setOriginPath, + }; +} diff --git a/src/common/useRouteFocused.ts b/src/common/useRouteFocused.ts new file mode 100644 index 000000000..80037f7d3 --- /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/ContinueWatchingItem/ContinueWatchingItem.js b/src/components/ContinueWatchingItem/ContinueWatchingItem.js index 8a0143619..8334cb796 100644 --- a/src/components/ContinueWatchingItem/ContinueWatchingItem.js +++ b/src/components/ContinueWatchingItem/ContinueWatchingItem.js @@ -1,23 +1,28 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); +const { useNavigate } = require('react-router'); const PropTypes = require('prop-types'); const { useServices } = require('stremio/services'); const LibItem = require('stremio/components/LibItem'); const ContinueWatchingItem = ({ _id, notifications, deepLinks, ...props }) => { const { core } = useServices(); + const navigate = useNavigate(); const onClick = React.useCallback(() => { if (deepLinks?.metaDetailsVideos ?? deepLinks?.metaDetailsStreams) { - window.location = deepLinks?.metaDetailsVideos ?? deepLinks?.metaDetailsStreams; + // TODO - remove # from deeplinks in core if possible + const navigateTo = deepLinks?.metaDetailsVideos ?? deepLinks?.metaDetailsStreams; + navigate(navigateTo.replace('#', '')); } }, [deepLinks]); const onPlayClick = React.useCallback((event) => { event.stopPropagation(); if (deepLinks?.player ?? deepLinks?.metaDetailsStreams ?? deepLinks?.metaDetailsVideos) { - window.location = deepLinks?.player ?? deepLinks?.metaDetailsStreams ?? deepLinks?.metaDetailsVideos; + const navigateTo = deepLinks?.player ?? deepLinks?.metaDetailsStreams ?? deepLinks?.metaDetailsVideos; + navigate(navigateTo.replace('#', '')); } }, [deepLinks]); diff --git a/src/components/LibItem/LibItem.js b/src/components/LibItem/LibItem.js index a42def27f..e618ee804 100644 --- a/src/components/LibItem/LibItem.js +++ b/src/components/LibItem/LibItem.js @@ -1,14 +1,15 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); +const { useNavigate } = require('react-router'); 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 +51,8 @@ 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; + // TODO: remove # from deeplinks in core for web? + navigate(props.deepLinks.player.replace('#', '')); } 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(props.deepLinks.metaDetailsVideos.replace('#', '')); } else if (typeof props.deepLinks.metaDetailsStreams === 'string') { - window.location = props.deepLinks.metaDetailsStreams; + navigate(props.deepLinks.metaDetailsStreams.replace('#', '')); } } diff --git a/src/components/MainNavBars/MainNavBars.tsx b/src/components/MainNavBars/MainNavBars.tsx index 43d08f5c8..a42273eab 100644 --- a/src/components/MainNavBars/MainNavBars.tsx +++ b/src/components/MainNavBars/MainNavBars.tsx @@ -6,12 +6,12 @@ import { VerticalNavBar, HorizontalNavBar } from 'stremio/components/NavBar'; 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 1e19054c1..eec59cefb 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 b07481f69..44f1f1fdb 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 6be35cd5d..e1f418ddd 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'); @@ -12,9 +13,14 @@ const NavMenu = require('./NavMenu'); const styles = require('./styles'); const { t } = require('i18next'); -const HorizontalNavBar = React.memo(({ className, route, query, title, backButton, searchBar, fullscreenButton, navMenu, ...props }) => { +const HorizontalNavBar = React.memo(({ className, route, query, title, backButton, searchBar, fullscreenButton, navMenu, originPath, ...props }) => { + const navigate = useNavigate(); const backButtonOnClick = React.useCallback(() => { - window.history.back(); + if (originPath) { + navigate(originPath); + } else { + navigate(-1); + } }, []); const [fullscreen, requestFullscreen, exitFullscreen] = useFullscreen(); const [isIOSPWA] = usePWA(); @@ -82,7 +88,8 @@ HorizontalNavBar.propTypes = { backButton: PropTypes.bool, searchBar: PropTypes.bool, fullscreenButton: PropTypes.bool, - navMenu: PropTypes.bool + navMenu: PropTypes.bool, + originPath: PropTypes.string, }; module.exports = HorizontalNavBar; diff --git a/src/components/NavBar/HorizontalNavBar/NavMenu/NavMenu.js b/src/components/NavBar/HorizontalNavBar/NavMenu/NavMenu.js index 8d381f3ca..b5de0ee71 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 de0a02212..72531ba6c 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'); @@ -17,6 +18,7 @@ const styles = require('./styles'); const NavMenuContent = ({ onClick }) => { const { t } = useTranslation(); + const navigate = useNavigate(); const { core } = useServices(); const profile = useProfile(); const streamingServer = useStreamingServer(); @@ -45,6 +47,12 @@ const NavMenuContent = ({ onClick }) => { console.error(e); } }, []); + const handleAuth = React.useCallback(() => { + return profile.auth !== null + ? logoutButtonOnClick() + : navigate('/intro'); + }, [profile.auth, logoutButtonOnClick, navigate]); + return (
@@ -64,7 +72,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 0bc95cd73..885dd196f 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 useTorrent = require('stremio/common/useTorrent'); @@ -22,16 +24,17 @@ const SearchBar = React.memo(({ className, query, active }) => { const searchHistory = useSearchHistory(); const localSearch = useLocalSearch(); const { createTorrentFromMagnet } = useTorrent(); + const navigate = useNavigate(); 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]); @@ -64,7 +67,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(); } }, []); @@ -72,7 +75,7 @@ const SearchBar = React.memo(({ className, query, active }) => { const queryInputClear = React.useCallback(() => { searchInputRef.current.value = ''; setCurrentQuery(''); - window.location.hash = '/search'; + navigate('/search', { 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 65c6a02a9..e59f106f7 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 ( -