temp move

This commit is contained in:
Carl-Gerhard Lindesvärd
2024-03-19 23:22:59 +01:00
parent 303c4060f3
commit e4643ce63e
249 changed files with 9 additions and 2 deletions

View File

@@ -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;
}

View File

@@ -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>;
}

View File

@@ -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,
};
}

View File

@@ -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;
}

View File

@@ -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 ?? [];
}

View File

@@ -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 ?? [];
}

View File

@@ -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));
}

View File

@@ -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 ?? [];
}

View File

@@ -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
);
}

View File

@@ -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;
};
}

View File

@@ -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}` : ''}`;
},
};
}

View File

@@ -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 ?? [];
}

View File

@@ -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 ?? [];
}

View File

@@ -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]);
}

View File

@@ -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]
);
}

View File

@@ -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]);
}