Merge branch 'dev' into boards
# Conflicts: # .gitignore # package.json # pnpm-lock.yaml # prisma/migrations/16_boards/migration.sql # prisma/schema.prisma # src/app/(main)/MobileNav.tsx # src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx # src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx # src/components/common/SideMenu.tsx # src/lib/types.ts
This commit is contained in:
commit
c3e0290e65
150 files changed
+3028
-787
No files matched your search
@@ -0,0 +1,6 @@
|
||||
import { useContext } from 'react';
|
||||
import { ShareContext } from '@/app/share/ShareProvider';
|
||||
|
||||
export function useShare() {
|
||||
return useContext(ShareContext);
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
export * from './context/useBoard';
|
||||
export * from './context/useLink';
|
||||
export * from './context/usePixel';
|
||||
export * from './context/useShare';
|
||||
export * from './context/useTeam';
|
||||
export * from './context/useUser';
|
||||
export * from './context/useWebsite';
|
||||
@@ -54,6 +55,7 @@ export * from './queries/useWebsiteSegmentsQuery';
|
||||
export * from './queries/useWebsiteSessionQuery';
|
||||
export * from './queries/useWebsiteSessionStatsQuery';
|
||||
export * from './queries/useWebsiteSessionsQuery';
|
||||
export * from './queries/useWebsiteSharesQuery';
|
||||
export * from './queries/useWebsiteStatsQuery';
|
||||
export * from './queries/useWebsitesQuery';
|
||||
export * from './queries/useWebsiteValuesQuery';
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useDateParameters } from '@/components/hooks/useDateParameters';
|
||||
import { useApi } from '../useApi';
|
||||
import { useFilterParameters } from '../useFilterParameters';
|
||||
|
||||
export interface EventStatsData {
|
||||
events: number;
|
||||
visitors: number;
|
||||
visits: number;
|
||||
uniqueEvents: number;
|
||||
}
|
||||
|
||||
type EventStatsApiResponse = {
|
||||
data: EventStatsData;
|
||||
};
|
||||
|
||||
export function useEventStatsQuery(
|
||||
{ websiteId }: { websiteId: string },
|
||||
options?: UseQueryOptions<EventStatsApiResponse, Error, EventStatsData>,
|
||||
) {
|
||||
const { get, useQuery } = useApi();
|
||||
const { startAt, endAt } = useDateParameters();
|
||||
const filters = useFilterParameters();
|
||||
|
||||
return useQuery<EventStatsApiResponse, Error, EventStatsData>({
|
||||
queryKey: ['websites:events:stats', { websiteId, startAt, endAt, ...filters }],
|
||||
queryFn: () =>
|
||||
get(`/websites/${websiteId}/events/stats`, {
|
||||
startAt,
|
||||
endAt,
|
||||
...filters,
|
||||
}),
|
||||
select: response => response.data,
|
||||
enabled: !!websiteId,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
@@ -10,7 +10,7 @@ export function useResultQuery<T = any>(
|
||||
) {
|
||||
const { websiteId, ...parameters } = params;
|
||||
const { post, useQuery } = useApi();
|
||||
const { startDate, endDate, timezone } = useDateParameters();
|
||||
const { startDate, endDate, timezone, unit } = useDateParameters();
|
||||
const filters = useFilterParameters();
|
||||
|
||||
return useQuery<T>({
|
||||
@@ -22,6 +22,7 @@ export function useResultQuery<T = any>(
|
||||
startDate,
|
||||
endDate,
|
||||
timezone,
|
||||
unit,
|
||||
...params,
|
||||
...filters,
|
||||
},
|
||||
@@ -35,6 +36,7 @@ export function useResultQuery<T = any>(
|
||||
startDate,
|
||||
endDate,
|
||||
timezone,
|
||||
unit,
|
||||
...parameters,
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -1,25 +1,22 @@
|
||||
import { setShareToken, useApp } from '@/store/app';
|
||||
import { setShare, setShareToken, useApp } from '@/store/app';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
const selector = (state: { shareToken: string }) => state.shareToken;
|
||||
const selector = state => state.share;
|
||||
|
||||
export function useShareTokenQuery(slug: string): {
|
||||
shareToken: any;
|
||||
isLoading?: boolean;
|
||||
error?: Error;
|
||||
} {
|
||||
const shareToken = useApp(selector);
|
||||
export function useShareTokenQuery(slug: string) {
|
||||
const share = useApp(selector);
|
||||
const { get, useQuery } = useApi();
|
||||
const { isLoading, error } = useQuery({
|
||||
const query = useQuery({
|
||||
queryKey: ['share', slug],
|
||||
queryFn: async () => {
|
||||
const data = await get(`/share/${slug}`);
|
||||
|
||||
setShareToken(data);
|
||||
setShare(data);
|
||||
setShareToken({ token: data?.token });
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
return { shareToken, isLoading, error };
|
||||
return { share, ...query };
|
||||
}
|
||||
@@ -19,7 +19,7 @@ export function useWebsiteExpandedMetricsQuery(
|
||||
options?: ReactQueryOptions<WebsiteExpandedMetricsData>,
|
||||
) {
|
||||
const { get, useQuery } = useApi();
|
||||
const { startAt, endAt, unit, timezone } = useDateParameters();
|
||||
const { startAt, endAt } = useDateParameters();
|
||||
const filters = useFilterParameters();
|
||||
|
||||
return useQuery<WebsiteExpandedMetricsData>({
|
||||
@@ -29,8 +29,6 @@ export function useWebsiteExpandedMetricsQuery(
|
||||
websiteId,
|
||||
startAt,
|
||||
endAt,
|
||||
unit,
|
||||
timezone,
|
||||
...filters,
|
||||
...params,
|
||||
},
|
||||
@@ -39,8 +37,6 @@ export function useWebsiteExpandedMetricsQuery(
|
||||
get(`/websites/${websiteId}/metrics/expanded`, {
|
||||
startAt,
|
||||
endAt,
|
||||
unit,
|
||||
timezone,
|
||||
...filters,
|
||||
...params,
|
||||
}),
|
||||
|
||||
@@ -15,7 +15,7 @@ export function useWebsiteMetricsQuery(
|
||||
options?: ReactQueryOptions<WebsiteMetricsData>,
|
||||
) {
|
||||
const { get, useQuery } = useApi();
|
||||
const { startAt, endAt, unit, timezone } = useDateParameters();
|
||||
const { startAt, endAt } = useDateParameters();
|
||||
const filters = useFilterParameters();
|
||||
|
||||
return useQuery<WebsiteMetricsData>({
|
||||
@@ -25,8 +25,6 @@ export function useWebsiteMetricsQuery(
|
||||
websiteId,
|
||||
startAt,
|
||||
endAt,
|
||||
unit,
|
||||
timezone,
|
||||
...filters,
|
||||
...params,
|
||||
},
|
||||
@@ -35,8 +33,6 @@ export function useWebsiteMetricsQuery(
|
||||
get(`/websites/${websiteId}/metrics`, {
|
||||
startAt,
|
||||
endAt,
|
||||
unit,
|
||||
timezone,
|
||||
...filters,
|
||||
...params,
|
||||
}),
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import type { ReactQueryOptions } from '@/lib/types';
|
||||
import { useApi } from '../useApi';
|
||||
import { useModified } from '../useModified';
|
||||
import { usePagedQuery } from '../usePagedQuery';
|
||||
|
||||
export function useWebsiteSharesQuery(
|
||||
{ websiteId }: { websiteId: string },
|
||||
options?: ReactQueryOptions,
|
||||
) {
|
||||
const { modified } = useModified('shares');
|
||||
const { get } = useApi();
|
||||
|
||||
return usePagedQuery({
|
||||
queryKey: ['websiteShares', { websiteId, modified }],
|
||||
queryFn: pageParams => {
|
||||
return get(`/websites/${websiteId}/shares`, pageParams);
|
||||
},
|
||||
...options,
|
||||
});
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useDateParameters } from '@/components/hooks/useDateParameters';
|
||||
import { useDateRange } from '@/components/hooks/useDateRange';
|
||||
import { useApi } from '../useApi';
|
||||
import { useFilterParameters } from '../useFilterParameters';
|
||||
|
||||
@@ -20,21 +19,16 @@ export interface WebsiteStatsData {
|
||||
}
|
||||
|
||||
export function useWebsiteStatsQuery(
|
||||
websiteId: string,
|
||||
{ websiteId, compare }: { websiteId: string; compare?: string },
|
||||
options?: UseQueryOptions<WebsiteStatsData, Error, WebsiteStatsData>,
|
||||
) {
|
||||
const { get, useQuery } = useApi();
|
||||
const { startAt, endAt, unit, timezone } = useDateParameters();
|
||||
const { compare } = useDateRange();
|
||||
const { startAt, endAt } = useDateParameters();
|
||||
const filters = useFilterParameters();
|
||||
|
||||
return useQuery<WebsiteStatsData>({
|
||||
queryKey: [
|
||||
'websites:stats',
|
||||
{ websiteId, startAt, endAt, unit, timezone, compare, ...filters },
|
||||
],
|
||||
queryFn: () =>
|
||||
get(`/websites/${websiteId}/stats`, { startAt, endAt, unit, timezone, compare, ...filters }),
|
||||
queryKey: ['websites:stats', { websiteId, compare, startAt, endAt, ...filters }],
|
||||
queryFn: () => get(`/websites/${websiteId}/stats`, { compare, startAt, endAt, ...filters }),
|
||||
enabled: !!websiteId,
|
||||
...options,
|
||||
});
|
||||
|
||||
@@ -12,13 +12,12 @@ export function useWeeklyTrafficQuery(websiteId: string, params?: Record<string,
|
||||
return useQuery({
|
||||
queryKey: [
|
||||
'sessions',
|
||||
{ websiteId, modified, startAt, endAt, unit, timezone, ...params, ...filters },
|
||||
{ websiteId, modified, startAt, endAt, timezone, ...params, ...filters },
|
||||
],
|
||||
queryFn: () => {
|
||||
return get(`/websites/${websiteId}/sessions/weekly`, {
|
||||
startAt,
|
||||
endAt,
|
||||
unit,
|
||||
timezone,
|
||||
...params,
|
||||
...filters,
|
||||
|
||||
@@ -7,13 +7,13 @@ import { getItem } from '@/lib/storage';
|
||||
|
||||
export function useDateRange(options: { ignoreOffset?: boolean; timezone?: string } = {}) {
|
||||
const {
|
||||
query: { date = '', offset = 0, compare = 'prev' },
|
||||
query: { date = '', unit = '', offset = 0, compare = 'prev' },
|
||||
} = useNavigation();
|
||||
const { locale } = useLocale();
|
||||
|
||||
const dateRange = useMemo(() => {
|
||||
const dateRangeObject = parseDateRange(
|
||||
date || getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE,
|
||||
unit,
|
||||
locale,
|
||||
options.timezone,
|
||||
);
|
||||
@@ -21,12 +21,13 @@ export function useDateRange(options: { ignoreOffset?: boolean; timezone?: strin
|
||||
return !options.ignoreOffset && offset
|
||||
? getOffsetDateRange(dateRangeObject, +offset)
|
||||
: dateRangeObject;
|
||||
}, [date, offset, options]);
|
||||
}, [date, unit, offset, options]);
|
||||
|
||||
const dateCompare = getCompareDate(compare, dateRange.startDate, dateRange.endDate);
|
||||
|
||||
return {
|
||||
date,
|
||||
unit,
|
||||
offset,
|
||||
compare,
|
||||
isAllTime: date.endsWith(`:all`),
|
||||
|
||||
@@ -1,23 +1,142 @@
|
||||
import { useMessages } from './useMessages';
|
||||
|
||||
export type FieldGroup = 'url' | 'sources' | 'location' | 'environment' | 'utm' | 'other';
|
||||
|
||||
export interface Field {
|
||||
name: string;
|
||||
filterLabel: string;
|
||||
label: string;
|
||||
group: FieldGroup;
|
||||
}
|
||||
|
||||
export function useFields() {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
const fields = [
|
||||
{ name: 'path', type: 'string', label: formatMessage(labels.path) },
|
||||
{ name: 'query', type: 'string', label: formatMessage(labels.query) },
|
||||
{ name: 'title', type: 'string', label: formatMessage(labels.pageTitle) },
|
||||
{ name: 'referrer', type: 'string', label: formatMessage(labels.referrer) },
|
||||
{ name: 'browser', type: 'string', label: formatMessage(labels.browser) },
|
||||
{ name: 'os', type: 'string', label: formatMessage(labels.os) },
|
||||
{ name: 'device', type: 'string', label: formatMessage(labels.device) },
|
||||
{ name: 'country', type: 'string', label: formatMessage(labels.country) },
|
||||
{ name: 'region', type: 'string', label: formatMessage(labels.region) },
|
||||
{ name: 'city', type: 'string', label: formatMessage(labels.city) },
|
||||
{ name: 'hostname', type: 'string', label: formatMessage(labels.hostname) },
|
||||
{ name: 'tag', type: 'string', label: formatMessage(labels.tag) },
|
||||
{ name: 'event', type: 'string', label: formatMessage(labels.event) },
|
||||
const fields: Field[] = [
|
||||
{
|
||||
name: 'path',
|
||||
filterLabel: formatMessage(labels.path),
|
||||
label: formatMessage(labels.path),
|
||||
group: 'url',
|
||||
},
|
||||
{
|
||||
name: 'query',
|
||||
filterLabel: formatMessage(labels.query),
|
||||
label: formatMessage(labels.query),
|
||||
group: 'url',
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
filterLabel: formatMessage(labels.pageTitle),
|
||||
label: formatMessage(labels.pageTitle),
|
||||
group: 'url',
|
||||
},
|
||||
{
|
||||
name: 'referrer',
|
||||
filterLabel: formatMessage(labels.referrer),
|
||||
label: formatMessage(labels.referrer),
|
||||
group: 'sources',
|
||||
},
|
||||
{
|
||||
name: 'country',
|
||||
filterLabel: formatMessage(labels.country),
|
||||
label: formatMessage(labels.country),
|
||||
group: 'location',
|
||||
},
|
||||
{
|
||||
name: 'region',
|
||||
filterLabel: formatMessage(labels.region),
|
||||
label: formatMessage(labels.region),
|
||||
group: 'location',
|
||||
},
|
||||
{
|
||||
name: 'city',
|
||||
filterLabel: formatMessage(labels.city),
|
||||
label: formatMessage(labels.city),
|
||||
group: 'location',
|
||||
},
|
||||
{
|
||||
name: 'browser',
|
||||
filterLabel: formatMessage(labels.browser),
|
||||
label: formatMessage(labels.browser),
|
||||
group: 'environment',
|
||||
},
|
||||
{
|
||||
name: 'os',
|
||||
filterLabel: formatMessage(labels.os),
|
||||
label: formatMessage(labels.os),
|
||||
group: 'environment',
|
||||
},
|
||||
{
|
||||
name: 'device',
|
||||
filterLabel: formatMessage(labels.device),
|
||||
label: formatMessage(labels.device),
|
||||
group: 'environment',
|
||||
},
|
||||
{
|
||||
name: 'utmSource',
|
||||
filterLabel: formatMessage(labels.source),
|
||||
label: formatMessage(labels.utmSource),
|
||||
group: 'utm',
|
||||
},
|
||||
{
|
||||
name: 'utmMedium',
|
||||
filterLabel: formatMessage(labels.medium),
|
||||
label: formatMessage(labels.utmMedium),
|
||||
group: 'utm',
|
||||
},
|
||||
{
|
||||
name: 'utmCampaign',
|
||||
filterLabel: formatMessage(labels.campaign),
|
||||
label: formatMessage(labels.utmCampaign),
|
||||
group: 'utm',
|
||||
},
|
||||
{
|
||||
name: 'utmContent',
|
||||
filterLabel: formatMessage(labels.content),
|
||||
label: formatMessage(labels.utmContent),
|
||||
group: 'utm',
|
||||
},
|
||||
{
|
||||
name: 'utmTerm',
|
||||
filterLabel: formatMessage(labels.term),
|
||||
label: formatMessage(labels.utmTerm),
|
||||
group: 'utm',
|
||||
},
|
||||
{
|
||||
name: 'hostname',
|
||||
filterLabel: formatMessage(labels.hostname),
|
||||
label: formatMessage(labels.hostname),
|
||||
group: 'other',
|
||||
},
|
||||
{
|
||||
name: 'distinctId',
|
||||
filterLabel: formatMessage(labels.distinctId),
|
||||
label: formatMessage(labels.distinctId),
|
||||
group: 'other',
|
||||
},
|
||||
{
|
||||
name: 'tag',
|
||||
filterLabel: formatMessage(labels.tag),
|
||||
label: formatMessage(labels.tag),
|
||||
group: 'other',
|
||||
},
|
||||
{
|
||||
name: 'event',
|
||||
filterLabel: formatMessage(labels.event),
|
||||
label: formatMessage(labels.event),
|
||||
group: 'other',
|
||||
},
|
||||
];
|
||||
|
||||
return { fields };
|
||||
const groupLabels: { key: FieldGroup; label: string }[] = [
|
||||
{ key: 'url', label: formatMessage(labels.url) },
|
||||
{ key: 'sources', label: formatMessage(labels.sources) },
|
||||
{ key: 'location', label: formatMessage(labels.location) },
|
||||
{ key: 'environment', label: formatMessage(labels.environment) },
|
||||
{ key: 'utm', label: formatMessage(labels.utm) },
|
||||
{ key: 'other', label: formatMessage(labels.other) },
|
||||
];
|
||||
|
||||
return { fields, groupLabels };
|
||||
}
|
||||
@@ -18,11 +18,18 @@ export function useFilterParameters() {
|
||||
event,
|
||||
tag,
|
||||
hostname,
|
||||
distinctId,
|
||||
utmSource,
|
||||
utmMedium,
|
||||
utmCampaign,
|
||||
utmContent,
|
||||
utmTerm,
|
||||
page,
|
||||
pageSize,
|
||||
search,
|
||||
segment,
|
||||
cohort,
|
||||
excludeBounce,
|
||||
},
|
||||
} = useNavigation();
|
||||
|
||||
@@ -42,9 +49,16 @@ export function useFilterParameters() {
|
||||
event,
|
||||
tag,
|
||||
hostname,
|
||||
distinctId,
|
||||
utmSource,
|
||||
utmMedium,
|
||||
utmCampaign,
|
||||
utmContent,
|
||||
utmTerm,
|
||||
search,
|
||||
segment,
|
||||
cohort,
|
||||
excludeBounce,
|
||||
};
|
||||
}, [
|
||||
path,
|
||||
@@ -61,10 +75,17 @@ export function useFilterParameters() {
|
||||
event,
|
||||
tag,
|
||||
hostname,
|
||||
distinctId,
|
||||
utmSource,
|
||||
utmMedium,
|
||||
utmCampaign,
|
||||
utmContent,
|
||||
utmTerm,
|
||||
page,
|
||||
pageSize,
|
||||
search,
|
||||
segment,
|
||||
cohort,
|
||||
excludeBounce,
|
||||
]);
|
||||
}
|
||||
Reference in new issue
Block a user