Refactor filter handling for queries.

This commit is contained in:
Mike Cao 2025-07-02 01:44:12 -07:00
parent 5b300f1ff5
commit ee6c68d27c
107 changed files with 731 additions and 835 deletions

View file

@ -24,7 +24,7 @@ export * from './queries/useTeamMembersQuery';
export * from './queries/useUserQuery';
export * from './queries/useUsersQuery';
export * from './queries/useWebsiteQuery';
export * from './queries/useWebsites';
export * from './queries/useWebsitesQuery';
export * from './queries/useWebsiteEventsQuery';
export * from './queries/useWebsiteEventsSeriesQuery';
export * from './queries/useWebsiteMetricsQuery';

View file

@ -1,6 +1,6 @@
import { useApi, useModified } from '@/components/hooks';
export function useDeleteQuery(path: string, params?: { [key: string]: any }) {
export function useDeleteQuery(path: string, params?: Record<string, any>) {
const { del, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({
mutationFn: () => del(path, params),

View file

@ -1,8 +1,27 @@
import { useTimezone } from '@/components/hooks/useTimezone';
import { REALTIME_INTERVAL } from '@/lib/constants';
import { RealtimeData } from '@/lib/types';
import { useApi } from '../useApi';
export interface RealtimeData {
countries: Record<string, number>;
events: any[];
pageviews: any[];
referrers: Record<string, number>;
timestamp: number;
series: {
views: any[];
visitors: any[];
};
totals: {
views: number;
visitors: number;
events: number;
countries: number;
};
urls: Record<string, number>;
visitors: any[];
}
export function useRealtimeQuery(websiteId: string) {
const { get, useQuery } = useApi();
const { timezone } = useTimezone();

View file

@ -4,7 +4,7 @@ import { ReactQueryOptions } from '@/lib/types';
export function useResultQuery<T = any>(
type: string,
params?: { [key: string]: any },
params?: Record<string, any>,
options?: ReactQueryOptions<T>,
) {
const { websiteId } = params;
@ -21,7 +21,7 @@ export function useResultQuery<T = any>(
...params,
},
],
queryFn: () => post(`/reports/${type}`, { type, ...filters, ...params }),
queryFn: () => post(`/reports/${type}`, { type, filters, ...params }),
enabled: !!type,
...options,
});

View file

@ -1,6 +1,6 @@
import { useApi } from '../useApi';
export function useUserQuery(userId: string, options?: { [key: string]: any }) {
export function useUserQuery(userId: string, options?: Record<string, any>) {
const { get, useQuery } = useApi();
return useQuery({
queryKey: ['users', userId],

View file

@ -5,11 +5,11 @@ import { ReactQueryOptions } from '@/lib/types';
export function useWebsiteEventsQuery(websiteId: string, options?: ReactQueryOptions<any>) {
const { get } = useApi();
const filterParams = useFilterParams(websiteId);
const queryParams = useFilterParams(websiteId);
return usePagedQuery({
queryKey: ['websites:events', { websiteId, ...filterParams }],
queryFn: () => get(`/websites/${websiteId}/events`, { ...filterParams, pageSize: 20 }),
queryKey: ['websites:events', { websiteId, ...queryParams }],
queryFn: () => get(`/websites/${websiteId}/events`, { ...queryParams, pageSize: 20 }),
enabled: !!websiteId,
...options,
});

View file

@ -15,7 +15,7 @@ export function useWebsiteMetricsQuery(
options?: ReactQueryOptions<WebsiteMetricsData>,
) {
const { get, useQuery } = useApi();
const filterParams = useFilterParams(websiteId);
const queryParams = useFilterParams(websiteId);
const searchParams = useSearchParams();
return useQuery<WebsiteMetricsData>({
@ -23,13 +23,13 @@ export function useWebsiteMetricsQuery(
'websites:metrics',
{
websiteId,
...filterParams,
...queryParams,
...params,
},
],
queryFn: async () =>
get(`/websites/${websiteId}/metrics`, {
...filterParams,
...queryParams,
[searchParams.get('view')]: undefined,
...params,
}),

View file

@ -12,11 +12,11 @@ export function useWebsitePageviewsQuery(
options?: ReactQueryOptions<WebsitePageviewsData>,
) {
const { get, useQuery } = useApi();
const filterParams = useFilterParams(websiteId);
const queryParams = useFilterParams(websiteId);
return useQuery<WebsitePageviewsData>({
queryKey: ['websites:pageviews', { websiteId, compare, ...filterParams }],
queryFn: () => get(`/websites/${websiteId}/pageviews`, { compare, ...filterParams }),
queryKey: ['websites:pageviews', { websiteId, compare, ...queryParams }],
queryFn: () => get(`/websites/${websiteId}/pageviews`, { compare, ...queryParams }),
enabled: !!websiteId,
...options,
});

View file

@ -1,6 +1,6 @@
import { useApi } from '../useApi';
export function useWebsiteQuery(websiteId: string, options?: { [key: string]: any }) {
export function useWebsiteQuery(websiteId: string, options?: Record<string, any>) {
const { get, useQuery } = useApi();
return useQuery({

View file

@ -1,10 +1,7 @@
import { useApi } from '../useApi';
import { useFilterParams } from '../useFilterParams';
export function useWebsiteSessionStatsQuery(
websiteId: string,
options?: { [key: string]: string },
) {
export function useWebsiteSessionStatsQuery(websiteId: string, options?: Record<string, string>) {
const { get, useQuery } = useApi();
const params = useFilterParams(websiteId);

View file

@ -5,7 +5,7 @@ import { useFilterParams } from '@/components/hooks/useFilterParams';
export function useWebsiteSessionsQuery(
websiteId: string,
params?: { [key: string]: string | number },
params?: Record<string, string | number>,
) {
const { get } = useApi();
const { modified } = useModified(`sessions`);

View file

@ -4,7 +4,7 @@ import { useFilterParams } from '@/components/hooks/useFilterParams';
export function useWebsiteSessionsWeeklyQuery(
websiteId: string,
params?: { [key: string]: string | number },
params?: Record<string, string | number>,
) {
const { get, useQuery } = useApi();
const { modified } = useModified(`sessions`);

View file

@ -19,15 +19,14 @@ export interface WebsiteStatsData {
export function useWebsiteStatsQuery(
websiteId: string,
compare?: string,
options?: UseQueryOptions<WebsiteStatsData, Error, WebsiteStatsData>,
) {
const { get, useQuery } = useApi();
const params = useFilterParams(websiteId);
const filterParams = useFilterParams(websiteId);
return useQuery<WebsiteStatsData>({
queryKey: ['websites:stats', { websiteId, ...params, compare }],
queryFn: () => get(`/websites/${websiteId}/stats`, { ...params, compare }),
queryKey: ['websites:stats', { websiteId, ...filterParams }],
queryFn: () => get(`/websites/${websiteId}/stats`, { ...filterParams }),
enabled: !!websiteId,
...options,
});

View file

@ -2,10 +2,12 @@ import { useApi } from '../useApi';
import { usePagedQuery } from '../usePagedQuery';
import { useLoginQuery } from './useLoginQuery';
import { useModified } from '../useModified';
import { ReactQueryOptions } from '@/lib/types';
export function useWebsites(
export function useWebsitesQuery(
{ userId, teamId }: { userId?: string; teamId?: string },
params?: { [key: string]: string | number },
params?: Record<string, any>,
options?: ReactQueryOptions,
) {
const { get } = useApi();
const { user } = useLoginQuery();
@ -13,10 +15,12 @@ export function useWebsites(
return usePagedQuery({
queryKey: ['websites', { userId, teamId, modified, ...params }],
queryFn: () => {
queryFn: pageParams => {
return get(teamId ? `/teams/${teamId}/websites` : `/users/${userId || user.id}/websites`, {
...params,
...pageParams,
});
},
...options,
});
}

View file

@ -40,7 +40,7 @@ export function useFormat() {
return languageNames[value?.split('-')[0]] || value;
};
const formatValue = (value: string, type: string, data?: { [key: string]: any }): string => {
const formatValue = (value: string, type: string, data?: Record<string, any>): string => {
switch (type) {
case 'os':
return formatOS(value);

View file

@ -15,7 +15,7 @@ export function useMessages(): any {
id: string;
defaultMessage: string;
},
values?: { [key: string]: string },
values?: Record<string, string>,
opts?: any,
) => {
return descriptor ? intl.formatMessage(descriptor, values, opts) : null;

View file

@ -9,11 +9,11 @@ export function useNavigation() {
const [, websiteId] = pathname.match(/\/websites\/([a-f0-9-]+)/) || [];
const query = Object.fromEntries(searchParams);
const updateParams = (params?: { [key: string]: string | number }) => {
const updateParams = (params?: Record<string, string | number>) => {
return !params ? pathname : buildUrl(pathname, { ...query, ...params });
};
const renderUrl = (path: string, params?: { [key: string]: string | number } | false) => {
const renderUrl = (path: string, params?: Record<string, string | number> | false) => {
return buildUrl(
teamId ? `/teams/${teamId}${path}` : path,
params === false ? {} : { ...query, ...params },

View file

@ -1,30 +1,27 @@
import { UseQueryOptions } from '@tanstack/react-query';
import { useState } from 'react';
import { PageResult, PageParams, PagedQueryResult } from '@/lib/types';
import { useApi } from './useApi';
import { useNavigation } from './useNavigation';
export function usePagedQuery<T = any>({
export function usePagedQuery({
queryKey,
queryFn,
...options
}: Omit<UseQueryOptions, 'queryFn'> & { queryFn: (params?: object) => any }): PagedQueryResult<T> {
}: Omit<UseQueryOptions, 'queryFn'> & { queryFn: (params?: object) => any }) {
const { query: queryParams } = useNavigation();
const [params, setParams] = useState<PageParams>({
search: '',
page: queryParams?.page || '1',
const [params, setParams] = useState({
search: queryParams?.search ?? '',
page: queryParams?.page ?? '1',
});
const { useQuery } = useApi();
const { data, ...query } = useQuery({
queryKey: [{ ...queryKey, ...params }],
queryFn: () => queryFn(params as any),
...options,
});
return {
result: data as PageResult<T>,
query,
...useQuery({
queryKey: [{ ...queryKey, ...params }],
queryFn: () => queryFn(params),
...options,
}),
params,
setParams,
};