temp move
This commit is contained in:
@@ -1,16 +0,0 @@
|
||||
import { useParams } from 'next/navigation';
|
||||
|
||||
// eslint-disable-next-line
|
||||
type AppParams = {
|
||||
organizationId: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export function useAppParams<T>() {
|
||||
const params = useParams<T & AppParams>();
|
||||
return {
|
||||
...(params ?? {}),
|
||||
organizationId: params?.organizationId,
|
||||
projectId: params?.projectId,
|
||||
} as T & AppParams;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import { theme } from '@/utils/theme';
|
||||
import { useMediaQuery } from 'react-responsive';
|
||||
import type { ScreensConfig } from 'tailwindcss/types/config';
|
||||
|
||||
const breakpoints = theme?.screens ?? {
|
||||
xs: '480px',
|
||||
sm: '640px',
|
||||
md: '768px',
|
||||
lg: '1024px',
|
||||
xl: '1280px',
|
||||
};
|
||||
|
||||
export function useBreakpoint<K extends string>(breakpointKey: K) {
|
||||
const breakpointValue = breakpoints[breakpointKey as keyof ScreensConfig];
|
||||
const bool = useMediaQuery({
|
||||
query: `(max-width: ${breakpointValue as string})`,
|
||||
});
|
||||
const capitalizedKey =
|
||||
breakpointKey[0]?.toUpperCase() + breakpointKey.substring(1);
|
||||
|
||||
type KeyAbove = `isAbove${Capitalize<K>}`;
|
||||
type KeyBelow = `isBelow${Capitalize<K>}`;
|
||||
|
||||
return {
|
||||
[breakpointKey]: Number(String(breakpointValue).replace(/[^0-9]/g, '')),
|
||||
[`isAbove${capitalizedKey}`]: !bool,
|
||||
[`isBelow${capitalizedKey}`]: bool,
|
||||
} as Record<K, number> & Record<KeyAbove | KeyBelow, boolean>;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { parseAsInteger, useQueryState } from 'nuqs';
|
||||
|
||||
export function useCursor() {
|
||||
const [cursor, setCursor] = useQueryState(
|
||||
'cursor',
|
||||
parseAsInteger
|
||||
.withOptions({ shallow: false, history: 'push' })
|
||||
.withDefault(0)
|
||||
);
|
||||
return {
|
||||
cursor,
|
||||
setCursor,
|
||||
};
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
export function useDebounceFn<T>(fn: T, ms = 500): T {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call
|
||||
const debouncedFn = debounce(fn as any, ms);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
debouncedFn.cancel();
|
||||
};
|
||||
});
|
||||
|
||||
return debouncedFn as T;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
|
||||
export function useEventNames(projectId: string) {
|
||||
const query = api.chart.events.useQuery({
|
||||
projectId: projectId,
|
||||
});
|
||||
|
||||
return query.data ?? [];
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
|
||||
export function useEventProperties(projectId: string, event?: string) {
|
||||
const query = api.chart.properties.useQuery({
|
||||
projectId: projectId,
|
||||
event,
|
||||
});
|
||||
|
||||
return query.data ?? [];
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
// prettier-ignore
|
||||
import type { Options as NuqsOptions } from 'nuqs';
|
||||
|
||||
import {
|
||||
createParser,
|
||||
parseAsArrayOf,
|
||||
parseAsString,
|
||||
useQueryState,
|
||||
} from 'nuqs';
|
||||
|
||||
const nuqsOptions = { history: 'push' } as const;
|
||||
|
||||
type Operator = 'is' | 'isNot' | 'contains' | 'doesNotContain';
|
||||
|
||||
export const eventQueryFiltersParser = createParser({
|
||||
parse: (query: string) => {
|
||||
if (query === '') return [];
|
||||
const filters = query.split(';');
|
||||
|
||||
return (
|
||||
filters.map((filter) => {
|
||||
const [key, operator, value] = filter.split(',');
|
||||
return {
|
||||
id: key!,
|
||||
name: key!,
|
||||
operator: (operator ?? 'is') as Operator,
|
||||
value: [decodeURIComponent(value!)],
|
||||
};
|
||||
}) ?? []
|
||||
);
|
||||
},
|
||||
serialize: (value) => {
|
||||
return value
|
||||
.map(
|
||||
(filter) =>
|
||||
`${filter.id},${filter.operator},${encodeURIComponent(filter.value[0] ?? '')}`
|
||||
)
|
||||
.join(';');
|
||||
},
|
||||
});
|
||||
|
||||
export function useEventQueryFilters(options: NuqsOptions = {}) {
|
||||
const [filters, setFilters] = useQueryState(
|
||||
'f',
|
||||
eventQueryFiltersParser.withDefault([]).withOptions({
|
||||
...nuqsOptions,
|
||||
...options,
|
||||
})
|
||||
);
|
||||
|
||||
const setFilter = useCallback(
|
||||
(
|
||||
name: string,
|
||||
value: string | number | boolean | undefined | null,
|
||||
operator: Operator = 'is'
|
||||
) => {
|
||||
setFilters((prev) => {
|
||||
const exists = prev.find((filter) => filter.name === name);
|
||||
if (exists) {
|
||||
// If same value is already set, remove the filter
|
||||
if (exists.value[0] === value) {
|
||||
return prev.filter((filter) => filter.name !== name);
|
||||
}
|
||||
|
||||
return prev.map((filter) => {
|
||||
if (filter.name === name) {
|
||||
return {
|
||||
...filter,
|
||||
operator,
|
||||
value: [String(value)],
|
||||
};
|
||||
}
|
||||
return filter;
|
||||
});
|
||||
}
|
||||
|
||||
return [
|
||||
...prev,
|
||||
{
|
||||
id: name,
|
||||
name,
|
||||
operator,
|
||||
value: [String(value)],
|
||||
},
|
||||
];
|
||||
});
|
||||
},
|
||||
[setFilters]
|
||||
);
|
||||
|
||||
return [filters, setFilter, setFilters] as const;
|
||||
}
|
||||
|
||||
export const eventQueryNamesFilter = parseAsArrayOf(parseAsString).withDefault(
|
||||
[]
|
||||
);
|
||||
|
||||
export function useEventQueryNamesFilter(options: NuqsOptions = {}) {
|
||||
return useQueryState('events', eventQueryNamesFilter.withOptions(options));
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
|
||||
export function useEventValues(
|
||||
projectId: string,
|
||||
event: string,
|
||||
property: string
|
||||
) {
|
||||
const query = api.chart.values.useQuery({
|
||||
projectId: projectId,
|
||||
event,
|
||||
property,
|
||||
});
|
||||
|
||||
return query.data?.values ?? [];
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import type { IInterval } from '@openpanel/validation';
|
||||
|
||||
export function formatDateInterval(interval: IInterval, date: Date): string {
|
||||
if (interval === 'hour' || interval === 'minute') {
|
||||
return new Intl.DateTimeFormat('en-GB', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
}).format(date);
|
||||
}
|
||||
|
||||
if (interval === 'month') {
|
||||
return new Intl.DateTimeFormat('en-GB', { month: 'short' }).format(date);
|
||||
}
|
||||
|
||||
if (interval === 'day') {
|
||||
return new Intl.DateTimeFormat('en-GB', {
|
||||
weekday: 'short',
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
}).format(date);
|
||||
}
|
||||
|
||||
return date.toISOString();
|
||||
}
|
||||
|
||||
export function useFormatDateInterval(interval: IInterval) {
|
||||
return (date: Date | string) =>
|
||||
formatDateInterval(
|
||||
interval,
|
||||
typeof date === 'string' ? new Date(date) : date
|
||||
);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import mappings from '@/mappings.json';
|
||||
|
||||
export function useMappings() {
|
||||
return (val: string | null) => {
|
||||
return mappings.find((item) => item.id === val)?.name ?? val;
|
||||
};
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import { round } from '@/utils/math';
|
||||
import { isNil } from 'ramda';
|
||||
|
||||
export function fancyMinutes(time: number) {
|
||||
const minutes = Math.floor(time / 60);
|
||||
const seconds = round(time - minutes * 60, 0);
|
||||
if (minutes === 0) return `${seconds}s`;
|
||||
return `${minutes}m ${seconds}s`;
|
||||
}
|
||||
|
||||
export const formatNumber =
|
||||
(locale: string) => (value: number | null | undefined) => {
|
||||
if (isNil(value)) {
|
||||
return 'N/A';
|
||||
}
|
||||
return new Intl.NumberFormat(locale, {
|
||||
maximumSignificantDigits: 20,
|
||||
}).format(value);
|
||||
};
|
||||
|
||||
export const shortNumber =
|
||||
(locale: string) => (value: number | null | undefined) => {
|
||||
if (isNil(value)) {
|
||||
return 'N/A';
|
||||
}
|
||||
return new Intl.NumberFormat(locale, {
|
||||
notation: 'compact',
|
||||
}).format(value);
|
||||
};
|
||||
|
||||
export function useNumber() {
|
||||
const locale = 'en-gb';
|
||||
const format = formatNumber(locale);
|
||||
const short = shortNumber(locale);
|
||||
return {
|
||||
format,
|
||||
short,
|
||||
shortWithUnit: (value: number | null | undefined, unit?: string | null) => {
|
||||
if (isNil(value)) {
|
||||
return 'N/A';
|
||||
}
|
||||
if (unit === 'min') {
|
||||
return fancyMinutes(value);
|
||||
}
|
||||
return `${short(value)}${unit ? ` ${unit}` : ''}`;
|
||||
},
|
||||
formatWithUnit: (
|
||||
value: number | null | undefined,
|
||||
unit?: string | null
|
||||
) => {
|
||||
if (isNil(value)) {
|
||||
return 'N/A';
|
||||
}
|
||||
if (unit === 'min') {
|
||||
return fancyMinutes(value);
|
||||
}
|
||||
return `${format(value)}${unit ? ` ${unit}` : ''}`;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
|
||||
export function useProfileProperties(projectId: string) {
|
||||
const query = api.profile.properties.useQuery({
|
||||
projectId: projectId,
|
||||
});
|
||||
|
||||
return query.data ?? [];
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { api } from '@/app/_trpc/client';
|
||||
|
||||
export function useProfileValues(projectId: string, property: string) {
|
||||
const query = api.profile.values.useQuery({
|
||||
projectId: projectId,
|
||||
property,
|
||||
});
|
||||
|
||||
return query.data?.values ?? [];
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import type { IChartData, IChartSerieDataItem } from '@/app/_trpc/client';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
|
||||
export type IRechartPayloadItem = IChartSerieDataItem & { color: string };
|
||||
|
||||
export function useRechartDataModel(series: IChartData['series']) {
|
||||
return useMemo(() => {
|
||||
return (
|
||||
series[0]?.data.map(({ date }) => {
|
||||
return {
|
||||
date,
|
||||
timestamp: new Date(date).getTime(),
|
||||
...series.reduce((acc, serie, idx) => {
|
||||
return {
|
||||
...acc,
|
||||
...serie.data.reduce(
|
||||
(acc2, item) => {
|
||||
if (item.date === date) {
|
||||
if (item.previous) {
|
||||
acc2[`${idx}:prev:count`] = item.previous.value;
|
||||
}
|
||||
acc2[`${idx}:count`] = item.count;
|
||||
acc2[`${idx}:payload`] = {
|
||||
...item,
|
||||
color: getChartColor(idx),
|
||||
} satisfies IRechartPayloadItem;
|
||||
}
|
||||
return acc2;
|
||||
},
|
||||
{} as Record<string, any>
|
||||
),
|
||||
};
|
||||
}, {}),
|
||||
};
|
||||
}) ?? []
|
||||
);
|
||||
}, [series]);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import throttle from 'lodash.throttle';
|
||||
|
||||
export function useThrottle(cb: () => void, delay: number) {
|
||||
const options = { leading: true, trailing: false }; // add custom lodash options
|
||||
const cbRef = useRef(cb);
|
||||
// use mutable ref to make useCallback/throttle not depend on `cb` dep
|
||||
useEffect(() => {
|
||||
cbRef.current = cb;
|
||||
});
|
||||
return useCallback(
|
||||
throttle(() => cbRef.current(), delay, options),
|
||||
[delay]
|
||||
);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import type { IChartData } from '@/app/_trpc/client';
|
||||
|
||||
export type IVisibleSeries = ReturnType<typeof useVisibleSeries>['series'];
|
||||
export function useVisibleSeries(data: IChartData, limit?: number | undefined) {
|
||||
const max = limit ?? 5;
|
||||
const [visibleSeries, setVisibleSeries] = useState<string[]>(
|
||||
data?.series?.slice(0, max).map((serie) => serie.name) ?? []
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setVisibleSeries(
|
||||
data?.series?.slice(0, max).map((serie) => serie.name) ?? []
|
||||
);
|
||||
}, [data, max]);
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
series: data.series
|
||||
.map((serie, index) => ({
|
||||
...serie,
|
||||
index,
|
||||
}))
|
||||
.filter((serie) => visibleSeries.includes(serie.name)),
|
||||
setVisibleSeries,
|
||||
} as const;
|
||||
}, [visibleSeries, data.series]);
|
||||
}
|
||||
Reference in New Issue
Block a user