From 553d5001f624ff9863840fbf0aa504c0d407b4bf Mon Sep 17 00:00:00 2001 From: alexsparkes Date: Sat, 7 Feb 2026 12:04:24 +0000 Subject: [PATCH] feat: Update navigation to item detail pages and enhance item ID handling --- src/components/Elements/MainModal/Main.jsx | 38 ++++++++++++++----- .../background/options/BackgroundOptions.jsx | 2 +- .../SuggestedPacks/SuggestedPacks.jsx | 2 +- src/features/misc/views/Discover.jsx | 26 +++++++++++-- src/features/quote/options/QuoteOptions.jsx | 2 +- src/router/routes.jsx | 8 ++-- 6 files changed, 58 insertions(+), 20 deletions(-) diff --git a/src/components/Elements/MainModal/Main.jsx b/src/components/Elements/MainModal/Main.jsx index 98d194d6..29666857 100644 --- a/src/components/Elements/MainModal/Main.jsx +++ b/src/components/Elements/MainModal/Main.jsx @@ -30,7 +30,7 @@ function MainModal({ modalClose, deepLinkData }) { // Memoize to prevent infinite loops in useEffect const effectiveDeepLinkData = useMemo( () => routerDeepLinkData || deepLinkData, - [location.pathname, deepLinkData] + [location.pathname, deepLinkData], ); // Derive currentTab from router location instead of state @@ -38,7 +38,9 @@ function MainModal({ modalClose, deepLinkData }) { const [currentSection, setCurrentSection] = useState(''); const [currentSectionName, setCurrentSectionName] = useState(''); - const [currentSubSection, setCurrentSubSection] = useState(effectiveDeepLinkData?.subSection || null); + const [currentSubSection, setCurrentSubSection] = useState( + effectiveDeepLinkData?.subSection || null, + ); const [productView, setProductView] = useState(null); const [resetDiscoverToAll, setResetDiscoverToAll] = useState(false); const [navigationTrigger, setNavigationTrigger] = useState(null); @@ -100,7 +102,11 @@ function MainModal({ modalClose, deepLinkData }) { return; } - if (effectiveDeepLinkData.itemId && effectiveDeepLinkData.collection && effectiveDeepLinkData.fromCollection) { + if ( + effectiveDeepLinkData.itemId && + effectiveDeepLinkData.collection && + effectiveDeepLinkData.fromCollection + ) { setNavigationTrigger({ type: 'collection', data: effectiveDeepLinkData.collection, @@ -165,14 +171,27 @@ function MainModal({ modalClose, deepLinkData }) { if (currentSectionName !== '' && currentSectionName !== sectionName) { setCurrentSubSection(null); } - const entry = { section, sectionName, subSection: (currentSectionName === '' || currentSectionName === sectionName) ? currentSubSection : null }; + const entry = { + section, + sectionName, + subSection: + currentSectionName === '' || currentSectionName === sectionName ? currentSubSection : null, + }; const current = historyRef.current[historyIndexRef.current]; - if (!current || current.sectionName !== sectionName || current.subSection !== entry.subSection) { + if ( + !current || + current.sectionName !== sectionName || + current.subSection !== entry.subSection + ) { historyRef.current = historyRef.current.slice(0, historyIndexRef.current + 1).concat(entry); historyIndexRef.current = historyRef.current.length - 1; updateNavButtons(); } if (currentTab === TAB_TYPES.DISCOVER) { + // Don't navigate away if we're viewing a specific item + if (effectiveDeepLinkData?.itemId) { + return; + } const sectionMap = { [t('modals.main.marketplace.all')]: 'all', [t('modals.main.marketplace.photo_packs')]: 'photo_packs', @@ -186,9 +205,10 @@ function MainModal({ modalClose, deepLinkData }) { } } else if (currentTab === TAB_TYPES.SETTINGS && sectionName) { // Include subsection in hash if it exists and we're not changing sections - const path = currentSubSection && (currentSectionName === '' || currentSectionName === sectionName) - ? `/${currentTab}/${sectionName}/${currentSubSection}` - : `/${currentTab}/${sectionName}`; + const path = + currentSubSection && (currentSectionName === '' || currentSectionName === sectionName) + ? `/${currentTab}/${sectionName}/${currentSubSection}` + : `/${currentTab}/${sectionName}`; navigate(path, { replace: true }); } }; @@ -282,7 +302,7 @@ function MainModal({ modalClose, deepLinkData }) { { - const itemId = pack.name; + const itemId = pack.id || pack.name; navigate(`/discover/item/${itemId}`); variables.stats.postEvent('marketplace', 'ItemPage viewed'); diff --git a/src/features/marketplace/components/SuggestedPacks/SuggestedPacks.jsx b/src/features/marketplace/components/SuggestedPacks/SuggestedPacks.jsx index ee418b29..7c6e6a3f 100644 --- a/src/features/marketplace/components/SuggestedPacks/SuggestedPacks.jsx +++ b/src/features/marketplace/components/SuggestedPacks/SuggestedPacks.jsx @@ -35,7 +35,7 @@ const SuggestedPacks = ({ category, limit = 4, minToShow = 2 }) => { // Navigate to specific item detail page const navigateToItem = (item) => { const itemId = item.id || item.name; - navigate(`/discover/${category}/${itemId}`); + navigate(`/discover/item/${itemId}`); }; return ( diff --git a/src/features/misc/views/Discover.jsx b/src/features/misc/views/Discover.jsx index 069db67c..c1ef968a 100644 --- a/src/features/misc/views/Discover.jsx +++ b/src/features/misc/views/Discover.jsx @@ -83,13 +83,15 @@ function DiscoverContent({ category, onBreadcrumbsChange, deepLinkData }) { } else { // Look up the item to determine its type const installed = JSON.parse(localStorage.getItem('installed')) || []; - const item = installed.find((i) => i.name === deepLinkData.itemId || i.id === deepLinkData.itemId); + const item = installed.find( + (i) => i.name === deepLinkData.itemId || i.id === deepLinkData.itemId, + ); if (item) { const typeMap = { - 'photos': 'packs', - 'quotes': 'packs', - 'settings': 'presets', + photos: 'packs', + quotes: 'packs', + settings: 'presets', }; pathSegment = typeMap[item.type] || 'packs'; } @@ -197,6 +199,22 @@ function DiscoverContent({ category, onBreadcrumbsChange, deepLinkData }) { } break; + case 'marketplace:navigation': + // Handle navigation from the iframe (website sends this when URL changes) + if (payload?.path) { + // Parse the path: /marketplace/packs/abc123 or /marketplace/presets/xyz789 + const pathParts = payload.path.split('/').filter(Boolean); + + if (pathParts.length >= 3 && pathParts[0] === 'marketplace') { + const itemId = pathParts[2]; + navigate(`/discover/item/${itemId}`); + } else if (pathParts.length === 2 && pathParts[0] === 'marketplace') { + // Category page like /marketplace?type=photo_packs + // Already on the category, no need to navigate + } + } + break; + default: break; } diff --git a/src/features/quote/options/QuoteOptions.jsx b/src/features/quote/options/QuoteOptions.jsx index 3e185347..f79901cb 100644 --- a/src/features/quote/options/QuoteOptions.jsx +++ b/src/features/quote/options/QuoteOptions.jsx @@ -338,7 +338,7 @@ const QuoteOptions = ({ currentSubSection, onSubSectionChange, sectionName }) => }; const handleToggle = (pack) => { - const itemId = pack.name; + const itemId = pack.id || pack.name; navigate(`/discover/item/${itemId}`); variables.stats.postEvent('marketplace', 'ItemPage viewed'); diff --git a/src/router/routes.jsx b/src/router/routes.jsx index 883e7bfd..a21b0dcb 100644 --- a/src/router/routes.jsx +++ b/src/router/routes.jsx @@ -45,10 +45,6 @@ export const routes = [ path: 'discover/:category', element:
, }, - { - path: 'discover/:category/:itemId', - element:
, - }, { path: 'discover/item/:itemId', element:
, @@ -61,6 +57,10 @@ export const routes = [ path: 'discover/collection/:collectionId/:itemId', element:
, }, + { + path: 'discover/:category/:itemId', + element:
, + }, { path: 'library', element:
,