From e1ad5d490b77624231e3776a31e951d5717ba234 Mon Sep 17 00:00:00 2001 From: alexsparkes Date: Tue, 28 Oct 2025 18:55:13 +0000 Subject: [PATCH] feat: implement deep linking support for marketplace items and tabs --- .gitignore | 1 + src/components/Elements/MainModal/Main.jsx | 28 +++- src/features/marketplace/views/Browse.jsx | 110 ++++++++++++-- src/features/marketplace/views/ItemPage.jsx | 22 ++- src/features/misc/modals/Modals.jsx | 18 ++- src/features/misc/views/Marketplace.jsx | 14 +- src/utils/deepLinking.js | 154 ++++++++++++++++++++ 7 files changed, 320 insertions(+), 27 deletions(-) create mode 100644 src/utils/deepLinking.js diff --git a/.gitignore b/.gitignore index 1fac51a3..7e6019d7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ node_modules/ build/ .idea/ dist/ +/docs # Files package-lock.json diff --git a/src/components/Elements/MainModal/Main.jsx b/src/components/Elements/MainModal/Main.jsx index 6d4cd48c..cb38811c 100644 --- a/src/components/Elements/MainModal/Main.jsx +++ b/src/components/Elements/MainModal/Main.jsx @@ -1,11 +1,12 @@ import variables from 'config/variables'; -import { Suspense, lazy, useState, memo } from 'react'; +import { Suspense, lazy, useState, memo, useEffect } from 'react'; import { MdClose } from 'react-icons/md'; import './scss/index.scss'; import { Tooltip } from 'components/Elements'; import ModalLoader from './components/ModalLoader'; import { TAB_TYPES } from './constants/tabConfig'; +import { updateHash, onHashChange } from 'utils/deepLinking'; const Settings = lazy(() => import('../../../features/misc/views/Settings')); const Addons = lazy(() => import('../../../features/misc/views/Addons')); @@ -18,8 +19,27 @@ const TAB_COMPONENTS = { [TAB_TYPES.MARKETPLACE]: Marketplace, }; -function MainModal({ modalClose }) { - const [currentTab, setCurrentTab] = useState(TAB_TYPES.SETTINGS); +function MainModal({ modalClose, deepLinkData }) { + // Initialize with deep link tab if provided, otherwise default to settings + const initialTab = deepLinkData?.tab || TAB_TYPES.SETTINGS; + const [currentTab, setCurrentTab] = useState(initialTab); + + useEffect(() => { + // Listen for hash changes while modal is open + const cleanup = onHashChange((linkData) => { + if (linkData && linkData.tab !== currentTab) { + setCurrentTab(linkData.tab); + } + }); + + return cleanup; + }, [currentTab]); + + const handleChangeTab = (newTab) => { + setCurrentTab(newTab); + // Update URL hash when tab changes + updateHash(`#${newTab}`); + }; const TabComponent = TAB_COMPONENTS[currentTab] || Settings; @@ -35,7 +55,7 @@ function MainModal({ modalClose }) { }> - + ); diff --git a/src/features/marketplace/views/Browse.jsx b/src/features/marketplace/views/Browse.jsx index 5a65ad22..4030cfc0 100644 --- a/src/features/marketplace/views/Browse.jsx +++ b/src/features/marketplace/views/Browse.jsx @@ -17,11 +17,23 @@ import { Header } from 'components/Layout/Settings'; import { Button } from 'components/Elements'; import { install, urlParser, uninstall } from 'utils/marketplace'; +import { updateHash } from 'utils/deepLinking'; + +// API v2 base URL +const API_V2_BASE = `${variables.constants.API_URL}/marketplace`; class Marketplace extends PureComponent { - constructor() { - super(); - this.state = { items: [], button: '', done: false, item: {}, collection: false, filter: '' }; + constructor(props) { + super(props); + this.state = { + items: [], + relatedItems: [], + button: '', + done: false, + item: {}, + collection: false, + filter: '', + }; this.buttons = { uninstall: (