kaneo (minimalist kanban) fork to experiment adding a tangled integration github.com/usekaneo/kaneo
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #1076 from tinsever/fix/issue-849-bug-parallel-browser-tabs-overwrite-each

fix(web): isolate active workspace per tab via URL

authored by

Andrej and committed by
GitHub
17de4b3c cb258b2e

+36 -29
+13 -3
apps/web/src/hooks/queries/workspace-users/use-active-workspace-user.ts
··· 1 1 import { useQuery } from "@tanstack/react-query"; 2 + import useAuth from "@/components/providers/auth-provider/hooks/use-auth"; 3 + import useActiveWorkspace from "@/hooks/queries/workspace/use-active-workspace"; 2 4 import { authClient } from "@/lib/auth-client"; 3 5 4 6 export const useGetActiveWorkspaceUser = () => { 7 + const { user } = useAuth(); 8 + const { data: workspace } = useActiveWorkspace(); 9 + 5 10 return useQuery({ 6 - queryKey: ["workspace-user", "active"], 11 + queryKey: ["workspace-user", "active", workspace?.id, user?.id], 12 + enabled: !!workspace?.id && !!user?.id, 7 13 queryFn: async () => { 8 - const { data, error } = await authClient.organization.getActiveMember(); 14 + const { data, error } = await authClient.organization.listMembers({ 15 + query: { 16 + organizationId: workspace?.id, 17 + }, 18 + }); 9 19 10 20 if (error) { 11 21 throw new Error(error.message || "Failed to get active workspace user"); 12 22 } 13 23 14 - return data; 24 + return data.members.find((member) => member.userId === user?.id) ?? null; 15 25 }, 16 26 }); 17 27 };
+22 -2
apps/web/src/hooks/queries/workspace/use-active-workspace.ts
··· 1 + import { useParams } from "@tanstack/react-router"; 1 2 import { authClient } from "@/lib/auth-client"; 2 3 3 4 function useActiveWorkspace() { 4 5 const { data: activeOrganization, error } = 5 6 authClient.useActiveOrganization(); 7 + const { data: organizations, isPending: isOrganizationsPending } = 8 + authClient.useListOrganizations(); 9 + const { workspaceId } = useParams({ 10 + strict: false, 11 + select: (params) => ({ 12 + workspaceId: 13 + "workspaceId" in params && typeof params.workspaceId === "string" 14 + ? params.workspaceId 15 + : undefined, 16 + }), 17 + }); 18 + 19 + const workspaceFromRoute = workspaceId 20 + ? organizations?.find((organization) => organization.id === workspaceId) 21 + : undefined; 22 + const workspace = workspaceFromRoute ?? activeOrganization; 23 + const isLoading = 24 + (!!workspaceId && isOrganizationsPending && !workspaceFromRoute) || 25 + (!workspace && !error); 6 26 7 27 return { 8 - data: activeOrganization, 28 + data: workspace, 9 29 error, 10 - isLoading: !activeOrganization && !error, 30 + isLoading, 11 31 isError: !!error, 12 32 }; 13 33 }
+1 -24
apps/web/src/routes/_layout/_authenticated/dashboard/workspace/$workspaceId.tsx
··· 1 - import { createFileRoute, Outlet, useNavigate } from "@tanstack/react-router"; 2 - import { useEffect } from "react"; 3 - import useActiveWorkspace from "@/hooks/queries/workspace/use-active-workspace"; 1 + import { createFileRoute, Outlet } from "@tanstack/react-router"; 4 2 5 3 export const Route = createFileRoute( 6 4 "/_layout/_authenticated/dashboard/workspace/$workspaceId", ··· 9 7 }); 10 8 11 9 function RouteComponent() { 12 - const { workspaceId } = Route.useParams(); 13 - 14 - const { data: activeWorkspace } = useActiveWorkspace(); 15 - const navigate = useNavigate(); 16 - 17 - useEffect(() => { 18 - // If we have an active workspace and it doesn't match the URL, redirect to the correct workspace 19 - if (activeWorkspace && activeWorkspace.id !== workspaceId) { 20 - navigate({ 21 - to: "/dashboard/workspace/$workspaceId", 22 - params: { workspaceId: activeWorkspace.id }, 23 - replace: true, // Replace current history entry to avoid back button issues 24 - }); 25 - } 26 - }, [activeWorkspace, workspaceId, navigate]); 27 - 28 - // Don't render anything if we're redirecting 29 - if (activeWorkspace && activeWorkspace.id !== workspaceId) { 30 - return null; 31 - } 32 - 33 10 return <Outlet />; 34 11 }