diff --git a/apps/web/src/contexts/ModulesFilterContext.tsx b/apps/web/src/contexts/ModulesFilterContext.tsx index e8ef26b..de3edc4 100644 --- a/apps/web/src/contexts/ModulesFilterContext.tsx +++ b/apps/web/src/contexts/ModulesFilterContext.tsx @@ -36,6 +36,8 @@ export interface ModulesFilterContextValue extends ModulesFilterState { setDueAfter: (v: string | null) => void; setDueBefore: (v: string | null) => void; updateFilter: (updater: (prev: ModulesFilterState) => Partial) => void; + /** Reset every filter back to defaults (e.g. when switching projects). */ + reset: () => void; } const defaultState: ModulesFilterState = { @@ -67,6 +69,8 @@ export function ModulesFilterProvider({ children }: { children: ReactNode }) { [], ); + const reset = useCallback(() => setState(defaultState), []); + const setSearch = useCallback((v: string) => { setState((prev) => ({ ...prev, search: v })); }, []); @@ -143,6 +147,7 @@ export function ModulesFilterProvider({ children }: { children: ReactNode }) { setDueAfter, setDueBefore, updateFilter, + reset, }), [ state, @@ -161,6 +166,7 @@ export function ModulesFilterProvider({ children }: { children: ReactNode }) { setDueAfter, setDueBefore, updateFilter, + reset, ], ); diff --git a/apps/web/src/pages/ModulesPage.tsx b/apps/web/src/pages/ModulesPage.tsx index 4bcfeb9..8dad5c9 100644 --- a/apps/web/src/pages/ModulesPage.tsx +++ b/apps/web/src/pages/ModulesPage.tsx @@ -157,6 +157,12 @@ function ModuleProgressCircle({ progress }: { progress: number }) { ); } +// The modules filter provider lives at the app-shell root and outlives this +// page, so its status/lead/member ids (which are project-specific) would carry +// over into another project. Track the project the filter was last set for at +// module scope so it survives remounts, and reset when the project changes. +let lastFilteredProjectId: string | undefined; + export function ModulesPage() { const { t } = useTranslation(); const { workspaceSlug, projectId } = useParams<{ @@ -164,6 +170,13 @@ export function ModulesPage() { projectId: string; }>(); const filter = useModulesFilter(); + const resetFilter = filter.reset; + useEffect(() => { + if (projectId && projectId !== lastFilteredProjectId) { + lastFilteredProjectId = projectId; + resetFilter(); + } + }, [projectId, resetFilter]); const [workspace, setWorkspace] = useState(null); const [project, setProject] = useState(null); const [modules, setModules] = useState([]); diff --git a/apps/web/src/pages/WorkspaceViewsPage.tsx b/apps/web/src/pages/WorkspaceViewsPage.tsx index 78f4ddf..3e95a71 100644 --- a/apps/web/src/pages/WorkspaceViewsPage.tsx +++ b/apps/web/src/pages/WorkspaceViewsPage.tsx @@ -183,6 +183,11 @@ export function WorkspaceViewsPage() { if (prevViewIdRef.current !== viewId) { prevViewIdRef.current = viewId; viewAppliedRef.current = false; + // Static views (all-issues, assigned, etc.) carry no saved filters, so + // clear any left over from a custom view instead of keeping them applied. + if (!isCustomViewId(viewId)) { + setFilters(parseWorkspaceViewFiltersFromSearchParams(new URLSearchParams())); + } } if (!workspaceSlug || !viewId || !isCustomViewId(viewId) || viewAppliedRef.current) return; viewAppliedRef.current = true;