Skip to content

Commit 3f96943

Browse files
committed
fix: filter when switching websites, hooks to websiteId
1 parent 79599fa commit 3f96943

File tree

3 files changed

+73
-32
lines changed

3 files changed

+73
-32
lines changed

apps/dashboard/app/(main)/websites/[id]/_components/filters/filters-section.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ export function FiltersSection() {
7474

7575
const handleSave = useCallback(
7676
(name: string) => {
77-
if (filters.length === 0) return;
77+
if (filters.length === 0) {
78+
return;
79+
}
7880
setIsSaving(true);
7981

8082
const result = editing
@@ -146,7 +148,9 @@ export function FiltersSection() {
146148
}, [editing, setFilters]);
147149

148150
const handleSaveEdit = useCallback(() => {
149-
if (!editing || filters.length === 0) return;
151+
if (!editing || filters.length === 0) {
152+
return;
153+
}
150154
setIsSaving(true);
151155
const result = updateFilter(editing.id, editing.name, filters);
152156
if (result.success) {
@@ -164,7 +168,9 @@ export function FiltersSection() {
164168
setIsDeletingAll(false);
165169
}, [deleteAllFilters]);
166170

167-
if (filters.length === 0) return null;
171+
if (filters.length === 0) {
172+
return null;
173+
}
168174

169175
return (
170176
<div className="angled-rectangle-gradient border-b bg-background">

apps/dashboard/app/(main)/websites/[id]/layout.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
"use client";
22

33
import { useQueryClient } from "@tanstack/react-query";
4-
import { useAtom } from "jotai";
4+
import { useAtom, useSetAtom } from "jotai";
55
import { useParams, usePathname } from "next/navigation";
6+
import { useLayoutEffect } from "react";
67
import { toast } from "sonner";
78
import { WebsiteErrorState } from "@/components/website-error-state";
89
import { useTrackingSetup } from "@/hooks/use-tracking-setup";
910
import { useWebsite } from "@/hooks/use-websites";
10-
import { isAnalyticsRefreshingAtom } from "@/stores/jotai/filterAtoms";
11+
import {
12+
currentFilterWebsiteIdAtom,
13+
isAnalyticsRefreshingAtom,
14+
} from "@/stores/jotai/filterAtoms";
1115
import { AnalyticsToolbar } from "./_components/analytics-toolbar";
1216
import { WebsiteTrackingSetupTab } from "./_components/tabs/tracking-setup-tab";
1317

@@ -32,6 +36,11 @@ export default function WebsiteLayout({ children }: WebsiteLayoutProps) {
3236
const pathname = usePathname();
3337
const queryClient = useQueryClient();
3438
const [isRefreshing, setIsRefreshing] = useAtom(isAnalyticsRefreshingAtom);
39+
const setCurrentFilterWebsiteId = useSetAtom(currentFilterWebsiteIdAtom);
40+
41+
useLayoutEffect(() => {
42+
setCurrentFilterWebsiteId(websiteId);
43+
}, [websiteId, setCurrentFilterWebsiteId]);
3544

3645
const isDemoRoute = pathname?.startsWith("/demo/");
3746
const hideToolbar = NO_TOOLBAR_ROUTES.some((route) =>

apps/dashboard/stores/jotai/filterAtoms.ts

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import dayjs from "dayjs";
33
export interface DynamicQueryFilter {
44
field: string;
55
operator:
6-
| "eq"
7-
| "ne"
8-
| "contains"
9-
| "not_contains"
10-
| "starts_with"
11-
| "in"
12-
| "not_in";
6+
| "eq"
7+
| "ne"
8+
| "contains"
9+
| "not_contains"
10+
| "starts_with"
11+
| "in"
12+
| "not_in";
1313
value: string | number | (string | number)[];
1414
}
1515

@@ -291,33 +291,57 @@ export const isAnalyticsRefreshingAtom = atom(false);
291291

292292
// --- Dynamic Query Filters (for shared package compatibility) ---
293293
/**
294-
* Atom for storing DynamicQueryFilter[] from @databuddy/shared
295-
* This is used for the analytics toolbar and shared across all website pages
294+
* Internal atom storing filters with their associated websiteId.
295+
* Filters are automatically cleared when accessing from a different website.
296+
*/
297+
const dynamicQueryFiltersBaseAtom = atom<{
298+
websiteId: string | null;
299+
filters: DynamicQueryFilter[];
300+
}>({ websiteId: null, filters: [] });
301+
302+
/** Atom to track current website context for filter scoping */
303+
export const currentFilterWebsiteIdAtom = atom<string | null>(null);
304+
305+
/**
306+
* Derived atom that returns filters only if they belong to the current website.
307+
* Automatically clears stale filters from other websites.
296308
*/
297-
export const dynamicQueryFiltersAtom = atom<DynamicQueryFilter[]>([]);
309+
export const dynamicQueryFiltersAtom = atom(
310+
(get) => {
311+
const { websiteId, filters } = get(dynamicQueryFiltersBaseAtom);
312+
const currentWebsiteId = get(currentFilterWebsiteIdAtom);
313+
if (currentWebsiteId && websiteId && currentWebsiteId !== websiteId) {
314+
return [];
315+
}
316+
return filters;
317+
},
318+
(get, set, newFilters: DynamicQueryFilter[]) => {
319+
const currentWebsiteId = get(currentFilterWebsiteIdAtom);
320+
set(dynamicQueryFiltersBaseAtom, {
321+
websiteId: currentWebsiteId,
322+
filters: newFilters,
323+
});
324+
}
325+
);
298326

299327
/**
300328
* Action atom for adding a new dynamic query filter.
301329
* Adds the filter if it doesn't already exist (based on field and value).
302330
*/
303331
export const addDynamicFilterAtom = atom(
304332
null,
305-
(_get, set, filter: DynamicQueryFilter) => {
306-
set(dynamicQueryFiltersAtom, (prev) => {
307-
// Check if a filter with the same field and value already exists
308-
const isDuplicate = prev.some(
309-
(existing) =>
310-
existing.field === filter.field &&
311-
existing.value === filter.value &&
312-
existing.operator === filter.operator
313-
);
314-
315-
if (isDuplicate) {
316-
return prev; // Don't add duplicate filters
317-
}
333+
(get, set, filter: DynamicQueryFilter) => {
334+
const prev = get(dynamicQueryFiltersAtom);
335+
const isDuplicate = prev.some(
336+
(existing) =>
337+
existing.field === filter.field &&
338+
existing.value === filter.value &&
339+
existing.operator === filter.operator
340+
);
318341

319-
return [...prev, filter];
320-
});
342+
if (!isDuplicate) {
343+
set(dynamicQueryFiltersAtom, [...prev, filter]);
344+
}
321345
}
322346
);
323347

@@ -327,8 +351,10 @@ export const addDynamicFilterAtom = atom(
327351
*/
328352
export const removeDynamicFilterAtom = atom(
329353
null,
330-
(_get, set, filter: Partial<DynamicQueryFilter>) => {
331-
set(dynamicQueryFiltersAtom, (prev) =>
354+
(get, set, filter: Partial<DynamicQueryFilter>) => {
355+
const prev = get(dynamicQueryFiltersAtom);
356+
set(
357+
dynamicQueryFiltersAtom,
332358
prev.filter(
333359
(existing) =>
334360
!(

0 commit comments

Comments
 (0)