diff --git a/static/app/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState.spec.tsx b/static/app/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState.spec.tsx index 5aa893fedc61c7..14699c62509660 100644 --- a/static/app/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState.spec.tsx +++ b/static/app/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState.spec.tsx @@ -202,4 +202,25 @@ describe('useCurrentProjectState', () => { act(() => result.current.setCurrentProject(angular)); expect(result.current.currentProject).toBe(angular); }); + + it('should update when the page filters store changes', () => { + ProjectsStore.loadInitialData([javascript, angular]); + mockPageFilterStore([angular]); + const {result} = renderHook(useCurrentProjectState, { + initialProps: { + currentPanel: SidebarPanelKey.FEEDBACK_ONBOARDING, + targetPanel: SidebarPanelKey.FEEDBACK_ONBOARDING, + onboardingPlatforms: feedbackOnboardingPlatforms, + allPlatforms: feedbackOnboardingPlatforms, + }, + wrapper: createWrapper(), + }); + + // Starts with angular + expect(result.current.currentProject).toBe(angular); + + // Changes to javascript when page filters change + act(() => mockPageFilterStore([javascript])); + expect(result.current.currentProject).toBe(javascript); + }); }); diff --git a/static/app/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState.tsx b/static/app/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState.tsx index 3431f20cf74db1..2d2b0060853770 100644 --- a/static/app/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState.tsx +++ b/static/app/components/onboarding/gettingStartedDoc/utils/useCurrentProjectState.tsx @@ -1,4 +1,4 @@ -import {useEffect, useMemo, useState} from 'react'; +import {useCallback, useEffect, useMemo, useState} from 'react'; import partition from 'lodash/partition'; import type {SidebarPanelKey} from 'sentry/components/sidebar/types'; @@ -23,44 +23,27 @@ function useCurrentProjectState({ }: Props) { const {projects, initiallyLoaded: projectsLoaded} = useProjects(); const {selection, isReady} = useLegacyStore(PageFiltersStore); - const [currentProject, setCurrentProject] = useState(undefined); const {getParamValue: projectIds} = useUrlParams('project'); const projectId = projectIds()?.split('&').at(0); const isActive = currentPanel === targetPanel; // Projects with onboarding instructions - const projectsWithOnboarding = projects.filter( - p => p.platform && onboardingPlatforms.includes(p.platform) + const projectsWithOnboarding = useMemo( + () => projects.filter(p => p.platform && onboardingPlatforms.includes(p.platform)), + [projects, onboardingPlatforms] ); const [supportedProjects, unsupportedProjects] = useMemo(() => { return partition(projects, p => p.platform && allPlatforms.includes(p.platform)); }, [projects, allPlatforms]); - useEffect(() => { - if (!isActive) { - setCurrentProject(undefined); - return; - } - - if ( - currentProject || - !projectsLoaded || - !projects.length || - !isReady || - !projectsWithOnboarding || - !supportedProjects - ) { - return; - } - - if (projectId) { - setCurrentProject(projects.find(p => p.id === projectId) ?? undefined); - return; - } + const getDefaultCurrentProjectFromSelection = useCallback( + (selectionProjects: number[]): Project | undefined => { + if (!isActive || !selectionProjects.length) { + return undefined; + } - if (selection.projects.length) { - const selectedProjectIds = selection.projects.map(String); + const selectedProjectIds = selectionProjects.map(String); // If we selected something that has onboarding instructions, pick that first const projectForOnboarding = projectsWithOnboarding.find(p => @@ -68,8 +51,7 @@ function useCurrentProjectState({ ); if (projectForOnboarding) { - setCurrentProject(projectForOnboarding); - return; + return projectForOnboarding; } // If we selected something that supports the product pick that @@ -78,30 +60,73 @@ function useCurrentProjectState({ ); if (projectSupportsProduct) { - setCurrentProject(projectSupportsProduct); - return; + return projectSupportsProduct; } // Otherwise, just pick the first selected project - const firstSelectedProject = projects.find(p => selectedProjectIds.includes(p.id)); - setCurrentProject(firstSelectedProject); - return; + return projects.find(p => selectedProjectIds.includes(p.id)); + }, + [isActive, projects, projectsWithOnboarding, supportedProjects] + ); + + const getDefaultCurrentProject = useCallback((): Project | undefined => { + if (!isActive) { + return undefined; + } + + if ( + !projectsLoaded || + !projects.length || + !isReady || + !projectsWithOnboarding || + !supportedProjects + ) { + return undefined; + } + + if (projectId) { + return projects.find(p => p.id === projectId); } - // No selection, so pick the first project with onboarding - setCurrentProject(projectsWithOnboarding.at(0) || supportedProjects.at(0)); - return; + + return ( + getDefaultCurrentProjectFromSelection(selection.projects) ?? + projectsWithOnboarding.at(0) ?? + supportedProjects.at(0) + ); }, [ - currentProject, - projectsLoaded, - projects, - isReady, + getDefaultCurrentProjectFromSelection, isActive, - selection.projects, + isReady, + projectId, + projects, + projectsLoaded, projectsWithOnboarding, + selection.projects, supportedProjects, - projectId, ]); + const defaultCurrentProject = getDefaultCurrentProject(); + + const [currentProject, setCurrentProject] = useState( + defaultCurrentProject + ); + + // Update default project if none is set + useEffect(() => { + if (!isActive) { + return; + } + setCurrentProject(oldProject => oldProject ?? defaultCurrentProject); + }, [setCurrentProject, defaultCurrentProject, isActive]); + + // Update the current project when the page filters store changes + useEffect(() => { + const newSelectionProject = getDefaultCurrentProjectFromSelection(selection.projects); + if (newSelectionProject) { + setCurrentProject(newSelectionProject); + } + }, [selection.projects, getDefaultCurrentProjectFromSelection]); + return { projects: supportedProjects, allProjects: projects,