chore(root): migrate to biome
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import { api } from '@/trpc/client';
|
||||
@@ -9,6 +8,7 @@ import { cn } from '@/utils/cn';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
import { isSameDay, isSameHour, isSameMonth } from 'date-fns';
|
||||
import { last } from 'ramda';
|
||||
import React, { useCallback } from 'react';
|
||||
import {
|
||||
Area,
|
||||
CartesianGrid,
|
||||
@@ -57,7 +57,7 @@ export function Chart({ data }: Props) {
|
||||
},
|
||||
{
|
||||
staleTime: 1000 * 60 * 10,
|
||||
}
|
||||
},
|
||||
);
|
||||
const { series, setVisibleSeries } = useVisibleSeries(data);
|
||||
const rechartData = useRechartDataModel(series);
|
||||
@@ -73,7 +73,7 @@ export function Chart({ data }: Props) {
|
||||
id: string,
|
||||
col1: string,
|
||||
col2: string,
|
||||
percentChange: number
|
||||
percentChange: number,
|
||||
) => (
|
||||
<linearGradient id={id} x1="0" y1="0" x2="100%" y2="0">
|
||||
<stop offset="0%" stopColor={col1} />
|
||||
@@ -177,29 +177,25 @@ export function Chart({ data }: Props) {
|
||||
x2="0"
|
||||
y2="1"
|
||||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.8}
|
||||
></stop>
|
||||
<stop offset="0%" stopColor={color} stopOpacity={0.8} />
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.1}
|
||||
></stop>
|
||||
/>
|
||||
</linearGradient>
|
||||
)}
|
||||
{gradientTwoColors(
|
||||
`hideAllButLastInterval_${serie.id}`,
|
||||
'rgba(0,0,0,0)',
|
||||
color,
|
||||
lastIntervalPercent
|
||||
lastIntervalPercent,
|
||||
)}
|
||||
{gradientTwoColors(
|
||||
`hideJustLastInterval_${serie.id}`,
|
||||
color,
|
||||
'rgba(0,0,0,0)',
|
||||
lastIntervalPercent
|
||||
lastIntervalPercent,
|
||||
)}
|
||||
</defs>
|
||||
<Line
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -11,6 +10,7 @@ import { useNumber } from '@/hooks/useNumerFormatter';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { DropdownMenuPortal } from '@radix-ui/react-dropdown-menu';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { round } from '@openpanel/common';
|
||||
import { NOT_SET_VALUE } from '@openpanel/constants';
|
||||
@@ -33,7 +33,7 @@ export function Chart({ data }: Props) {
|
||||
const number = useNumber();
|
||||
const series = useMemo(
|
||||
() => (isEditMode ? data.series : data.series.slice(0, limit || 10)),
|
||||
[data, isEditMode, limit]
|
||||
[data, isEditMode, limit],
|
||||
);
|
||||
const maxCount = Math.max(...series.map((serie) => serie.metrics[metric]));
|
||||
|
||||
@@ -41,7 +41,7 @@ export function Chart({ data }: Props) {
|
||||
<div
|
||||
className={cn(
|
||||
'flex flex-col text-sm',
|
||||
isEditMode ? 'card gap-2 p-4 text-base' : '-m-3 gap-1'
|
||||
isEditMode ? 'card gap-2 p-4 text-base' : '-m-3 gap-1',
|
||||
)}
|
||||
>
|
||||
{series.map((serie) => {
|
||||
@@ -56,7 +56,7 @@ export function Chart({ data }: Props) {
|
||||
<div
|
||||
className={cn(
|
||||
'relative',
|
||||
(isClickable || isDropDownEnabled) && 'cursor-pointer'
|
||||
(isClickable || isDropDownEnabled) && 'cursor-pointer',
|
||||
)}
|
||||
{...(isClickable && !isDropDownEnabled
|
||||
? { onClick: () => onClick?.(serie) }
|
||||
@@ -80,7 +80,7 @@ export function Chart({ data }: Props) {
|
||||
{serie.metrics.previous?.[metric]?.value}
|
||||
<div className="text-muted-foreground">
|
||||
{number.format(
|
||||
round((serie.metrics.sum / data.metrics.sum) * 100, 2)
|
||||
round((serie.metrics.sum / data.metrics.sum) * 100, 2),
|
||||
)}
|
||||
%
|
||||
</div>
|
||||
|
||||
@@ -33,12 +33,15 @@ function Loading() {
|
||||
return (
|
||||
<AspectContainer className="col gap-4 overflow-hidden">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<div key={index} className="row animate-pulse justify-between">
|
||||
<div className="h-4 w-2/5 rounded bg-def-200"></div>
|
||||
<div
|
||||
key={index as number}
|
||||
className="row animate-pulse justify-between"
|
||||
>
|
||||
<div className="h-4 w-2/5 rounded bg-def-200" />
|
||||
<div className="row w-1/5 gap-2">
|
||||
<div className="h-4 w-full rounded bg-def-200"></div>
|
||||
<div className="h-4 w-full rounded bg-def-200"></div>
|
||||
<div className="h-4 w-full rounded bg-def-200"></div>
|
||||
<div className="h-4 w-full rounded bg-def-200" />
|
||||
<div className="h-4 w-full rounded bg-def-200" />
|
||||
<div className="h-4 w-full rounded bg-def-200" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { useDebounceFn } from '@/hooks/useDebounceFn';
|
||||
import { useFormatDateInterval } from '@/hooks/useFormatDateInterval';
|
||||
import { useNumber } from '@/hooks/useNumerFormatter';
|
||||
import { isNil } from 'ramda';
|
||||
import { useRef, useState } from 'react';
|
||||
import type { AxisDomain } from 'recharts/types/util/types';
|
||||
|
||||
import type { IInterval } from '@openpanel/validation';
|
||||
@@ -60,10 +60,10 @@ export const useXAxisProps = (
|
||||
} = {
|
||||
hide: false,
|
||||
interval: 'auto',
|
||||
}
|
||||
},
|
||||
) => {
|
||||
const formatDate = useFormatDateInterval(
|
||||
interval === 'auto' ? 'day' : interval
|
||||
interval === 'auto' ? 'day' : interval,
|
||||
);
|
||||
return {
|
||||
height: hide ? 0 : 14,
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export function ReportChartLoading() {
|
||||
return <div className="h-full w-full animate-pulse rounded bg-def-100"></div>;
|
||||
return <div className="h-full w-full animate-pulse rounded bg-def-100" />;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ export function getDiffIndicator<A, B, C>(
|
||||
state: string | undefined | null,
|
||||
positive: A,
|
||||
negative: B,
|
||||
neutral: C
|
||||
neutral: C,
|
||||
): A | B | C {
|
||||
if (state === 'neutral' || !state) {
|
||||
return neutral;
|
||||
@@ -48,7 +48,7 @@ export function PreviousDiffIndicator({
|
||||
state,
|
||||
'bg-emerald-300',
|
||||
'bg-rose-300',
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
const number = useNumber();
|
||||
|
||||
@@ -72,14 +72,14 @@ export function PreviousDiffIndicator({
|
||||
className={cn(
|
||||
'flex items-center gap-1 font-mono font-medium',
|
||||
size === 'lg' && 'gap-2',
|
||||
className
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
`flex size-4 items-center justify-center rounded-full`,
|
||||
'flex size-4 items-center justify-center rounded-full',
|
||||
variant,
|
||||
size === 'lg' && 'size-8'
|
||||
size === 'lg' && 'size-8',
|
||||
)}
|
||||
>
|
||||
{renderIcon()}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useFormatDateInterval } from '@/hooks/useFormatDateInterval';
|
||||
import { useNumber } from '@/hooks/useNumerFormatter';
|
||||
import type { IRechartPayloadItem } from '@/hooks/useRechartDataModel';
|
||||
@@ -6,6 +5,7 @@ import type { IToolTipProps } from '@/types';
|
||||
import * as Portal from '@radix-ui/react-portal';
|
||||
import { bind } from 'bind-event-listener';
|
||||
import throttle from 'lodash.throttle';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { useReportChartContext } from '../context';
|
||||
import { PreviousDiffIndicator } from './previous-diff-indicator';
|
||||
@@ -29,7 +29,7 @@ export function ReportChartTooltip({
|
||||
const formatDate = useFormatDateInterval(interval);
|
||||
const number = useNumber();
|
||||
const [position, setPosition] = useState<{ x: number; y: number } | null>(
|
||||
null
|
||||
null,
|
||||
);
|
||||
|
||||
const inactive = !active || !payload?.length;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import * as React from 'react';
|
||||
import { Pagination, usePagination } from '@/components/pagination';
|
||||
import { Stats, StatsCard } from '@/components/stats';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
@@ -18,6 +17,7 @@ import { useSelector } from '@/redux';
|
||||
import { getPropertyLabel } from '@/translations/properties';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
import type * as React from 'react';
|
||||
|
||||
import { PreviousDiffIndicator } from './previous-diff-indicator';
|
||||
import { SerieName } from './serie-name';
|
||||
@@ -45,9 +45,8 @@ export function ReportTable({
|
||||
setVisibleSeries((prev) => {
|
||||
if (checked) {
|
||||
return [...prev, name];
|
||||
} else {
|
||||
return prev.filter((item) => item !== name);
|
||||
}
|
||||
return prev.filter((item) => item !== name);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,7 +76,7 @@ export function ReportTable({
|
||||
<TableBody className="bg-def-100">
|
||||
{paginate(data.series).map((serie, index) => {
|
||||
const checked = !!visibleSeries.find(
|
||||
(item) => item.id === serie.id
|
||||
(item) => item.id === serie.id,
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import type { LucideIcon, LucideProps } from 'lucide-react';
|
||||
|
||||
const createFlagIcon = (url: string) => {
|
||||
return function (_props: LucideProps) {
|
||||
return (
|
||||
<span
|
||||
className={`fi !block aspect-[1.33] overflow-hidden rounded-[2px] fi-${url}`}
|
||||
></span>
|
||||
);
|
||||
} as LucideIcon;
|
||||
return ((_props: LucideProps) => (
|
||||
<span
|
||||
className={`fi !block aspect-[1.33] overflow-hidden rounded-[2px] fi-${url}`}
|
||||
/>
|
||||
)) as LucideIcon;
|
||||
};
|
||||
|
||||
const data = {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { LucideIcon, LucideProps } from 'lucide-react';
|
||||
import {
|
||||
ActivityIcon,
|
||||
@@ -15,6 +14,7 @@ import {
|
||||
TabletIcon,
|
||||
TvIcon,
|
||||
} from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { NOT_SET_VALUE } from '@openpanel/constants';
|
||||
|
||||
@@ -30,9 +30,13 @@ function getProxyImage(url: string) {
|
||||
}
|
||||
|
||||
const createImageIcon = (url: string) => {
|
||||
return function (_props: LucideProps) {
|
||||
return <img className="max-h-4 rounded-[2px] object-contain" src={url} />;
|
||||
} as LucideIcon;
|
||||
return ((_props: LucideProps) => (
|
||||
<img
|
||||
alt="serie icon"
|
||||
className="max-h-4 rounded-[2px] object-contain"
|
||||
src={url}
|
||||
/>
|
||||
)) as LucideIcon;
|
||||
};
|
||||
|
||||
const mapper: Record<string, LucideIcon> = {
|
||||
@@ -60,7 +64,7 @@ const mapper: Record<string, LucideIcon> = {
|
||||
...acc,
|
||||
[key]: createImageIcon(getProxyImage(value)),
|
||||
}),
|
||||
{}
|
||||
{},
|
||||
),
|
||||
|
||||
...flags,
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
// prettier-ignore
|
||||
// biome-ignore format: annoying
|
||||
|
||||
const data = {
|
||||
'chromium os': 'https://upload.wikimedia.org/wikipedia/commons/2/28/Chromium_Logo.svg',
|
||||
'mac os': 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/30/MacOS_logo.svg/1200px-MacOS_logo.svg.png',
|
||||
'apple': 'https://sladesportfolio.wordpress.com/wp-content/uploads/2015/08/apple_logo_black-svg.png',
|
||||
'huawei': 'https://upload.wikimedia.org/wikipedia/en/0/04/Huawei_Standard_logo.svg',
|
||||
'xiaomi': 'https://upload.wikimedia.org/wikipedia/commons/2/29/Xiaomi_logo.svg',
|
||||
'sony': 'https://serialtrainer7.com/wp-content/uploads/2021/07/sony-logo-300px-square.png',
|
||||
'lg': 'https://upload.wikimedia.org/wikipedia/commons/2/20/LG_symbol.svg',
|
||||
'samsung': 'https://seekvectors.com/storage/images/Samsung-Logo-22.svg',
|
||||
'oppo': 'https://indoleads.nyc3.cdn.digitaloceanspaces.com/uploads/offers/logos/8695_95411e367b832.png',
|
||||
'motorola': 'https://upload.wikimedia.org/wikipedia/commons/8/8f/Motorola_M_symbol_blue.svg',
|
||||
'oneplus': 'https://pbs.twimg.com/profile_images/1709165009148809216/ebHb4xhF_400x400.png',
|
||||
'asus': 'https://cdn-icons-png.freepik.com/512/5969/5969050.png',
|
||||
'fairphone': 'https://cdn.dribbble.com/users/433772/screenshots/2109827/fairphone_dribbble.jpg',
|
||||
'nokia': 'https://www.gizchina.com/wp-content/uploads/images/2023/02/Nokia-logo.webp',
|
||||
apple: 'https://sladesportfolio.wordpress.com/wp-content/uploads/2015/08/apple_logo_black-svg.png',
|
||||
huawei: 'https://upload.wikimedia.org/wikipedia/en/0/04/Huawei_Standard_logo.svg',
|
||||
xiaomi: 'https://upload.wikimedia.org/wikipedia/commons/2/29/Xiaomi_logo.svg',
|
||||
sony: 'https://serialtrainer7.com/wp-content/uploads/2021/07/sony-logo-300px-square.png',
|
||||
lg: 'https://upload.wikimedia.org/wikipedia/commons/2/20/LG_symbol.svg',
|
||||
samsung: 'https://seekvectors.com/storage/images/Samsung-Logo-22.svg',
|
||||
oppo: 'https://indoleads.nyc3.cdn.digitaloceanspaces.com/uploads/offers/logos/8695_95411e367b832.png',
|
||||
motorola: 'https://upload.wikimedia.org/wikipedia/commons/8/8f/Motorola_M_symbol_blue.svg',
|
||||
oneplus: 'https://pbs.twimg.com/profile_images/1709165009148809216/ebHb4xhF_400x400.png',
|
||||
asus: 'https://cdn-icons-png.freepik.com/512/5969/5969050.png',
|
||||
fairphone: 'https://cdn.dribbble.com/users/433772/screenshots/2109827/fairphone_dribbble.jpg',
|
||||
nokia: 'https://www.gizchina.com/wp-content/uploads/images/2023/02/Nokia-logo.webp',
|
||||
'mobile safari': 'https://upload.wikimedia.org/wikipedia/commons/5/52/Safari_browser_logo.svg',
|
||||
'openpanel.dev': 'https://openpanel.dev',
|
||||
'samsung internet': 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e9/Samsung_Internet_logo.svg/1024px-Samsung_Internet_logo.svg.png',
|
||||
@@ -21,12 +22,12 @@ const data = {
|
||||
'yahoo!': 'https://yahoo.com',
|
||||
android: 'https://image.similarpng.com/very-thumbnail/2020/08/Android-icon-on-transparent--background-PNG.png',
|
||||
'android browser': 'https://image.similarpng.com/very-thumbnail/2020/08/Android-icon-on-transparent--background-PNG.png',
|
||||
'silk': 'https://m.media-amazon.com/images/I/51VCjQCvF0L.png',
|
||||
'kakaotalk': 'https://www.kakaocorp.com/',
|
||||
silk: 'https://m.media-amazon.com/images/I/51VCjQCvF0L.png',
|
||||
kakaotalk: 'https://www.kakaocorp.com/',
|
||||
bing: 'https://bing.com',
|
||||
'electron': 'https://www.electronjs.org',
|
||||
'whale': 'https://whale.naver.com',
|
||||
'wechat': 'https://wechat.com',
|
||||
electron: 'https://www.electronjs.org',
|
||||
whale: 'https://whale.naver.com',
|
||||
wechat: 'https://wechat.com',
|
||||
chrome: 'https://upload.wikimedia.org/wikipedia/commons/e/e1/Google_Chrome_icon_%28February_2022%29.svg',
|
||||
'chrome webview': 'https://upload.wikimedia.org/wikipedia/commons/e/e1/Google_Chrome_icon_%28February_2022%29.svg',
|
||||
'chrome headless': 'https://upload.wikimedia.org/wikipedia/commons/e/e1/Google_Chrome_icon_%28February_2022%29.svg',
|
||||
@@ -68,8 +69,8 @@ const data = {
|
||||
tiktok: 'https://tiktok.com',
|
||||
sharpspring: 'https://sharpspring.com',
|
||||
'hacker news': 'https://news.ycombinator.com',
|
||||
'betalist': 'https://betalist.com',
|
||||
'qwant': 'https://www.qwant.com',
|
||||
betalist: 'https://betalist.com',
|
||||
qwant: 'https://www.qwant.com',
|
||||
flipboard: 'https://flipboard.com/',
|
||||
trustpilot: 'https://trustpilot.com',
|
||||
'outlook.com': 'https://login.live.com/',
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ChevronRightIcon } from 'lucide-react';
|
||||
|
||||
import { NOT_SET_VALUE } from '@openpanel/constants';
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import { useReportChartContext } from '../context';
|
||||
|
||||
interface SerieNameProps {
|
||||
@@ -23,12 +24,12 @@ export function SerieName({ name, className }: SerieNameProps) {
|
||||
<div className={cn('flex items-center gap-1', className)}>
|
||||
{name.map((n, index) => {
|
||||
return (
|
||||
<>
|
||||
<Fragment key={n}>
|
||||
<span>{n || NOT_SET_VALUE}</span>
|
||||
{name.length - 1 > index && (
|
||||
<ChevronRightIcon className="text-muted-foreground" size={12} />
|
||||
)}
|
||||
</>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createContext, useContext, useEffect, useState } from 'react';
|
||||
import isEqual from 'lodash.isequal';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
import { createContext, useContext, useEffect, useState } from 'react';
|
||||
|
||||
import type {
|
||||
IChartInput,
|
||||
@@ -46,14 +46,14 @@ export const useReportChartContext = () => {
|
||||
const ctx = useContext(context);
|
||||
if (!ctx) {
|
||||
throw new Error(
|
||||
'useReportChartContext must be used within a ReportChartProvider'
|
||||
'useReportChartContext must be used within a ReportChartProvider',
|
||||
);
|
||||
}
|
||||
return ctx;
|
||||
};
|
||||
|
||||
export const useSelectReportChartContext = <T,>(
|
||||
selector: (ctx: ReportChartContextType) => T
|
||||
selector: (ctx: ReportChartContextType) => T,
|
||||
) => {
|
||||
const ctx = useReportChartContext();
|
||||
const [state, setState] = useState(selector(ctx));
|
||||
|
||||
@@ -17,7 +17,7 @@ import { PreviousDiffIndicator } from '../common/previous-diff-indicator';
|
||||
import { useReportChartContext } from '../context';
|
||||
|
||||
const findMostDropoffs = (
|
||||
steps: RouterOutputs['chart']['funnel']['current']['steps']
|
||||
steps: RouterOutputs['chart']['funnel']['current']['steps'],
|
||||
) => {
|
||||
return steps.reduce((acc, step) => {
|
||||
if (step.dropoffCount > acc.dropoffCount) {
|
||||
@@ -58,7 +58,7 @@ export function Chart({
|
||||
<div
|
||||
className={cn(
|
||||
'border border-border',
|
||||
!isEditMode && 'border-0 border-b'
|
||||
!isEditMode && 'border-0 border-b',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-8 p-4">
|
||||
@@ -72,7 +72,7 @@ export function Chart({
|
||||
<div
|
||||
className="w-full bg-def-400"
|
||||
style={{ height: `${step.percent}%` }}
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -129,7 +129,7 @@ export function Chart({
|
||||
<PreviousDiffIndicator
|
||||
{...getPreviousMetric(
|
||||
step.previousCount,
|
||||
previous.steps[index]?.previousCount
|
||||
previous.steps[index]?.previousCount,
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -160,7 +160,7 @@ export function Chart({
|
||||
inverted
|
||||
{...getPreviousMetric(
|
||||
step.dropoffCount,
|
||||
previous.steps[index]?.dropoffCount
|
||||
previous.steps[index]?.dropoffCount,
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -174,7 +174,7 @@ export function Chart({
|
||||
<span
|
||||
className={cn(
|
||||
'flex items-center gap-1 text-lg font-bold',
|
||||
isMostDropoffs && 'text-rose-500'
|
||||
isMostDropoffs && 'text-rose-500',
|
||||
)}
|
||||
>
|
||||
{isMostDropoffs && <AlertCircleIcon size={14} />}
|
||||
@@ -196,7 +196,7 @@ export function Chart({
|
||||
<PreviousDiffIndicator
|
||||
{...getPreviousMetric(
|
||||
step.count,
|
||||
previous.steps[index]?.count
|
||||
previous.steps[index]?.count,
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -208,7 +208,7 @@ export function Chart({
|
||||
</span>
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-lg font-bold">{step.count}</span>
|
||||
{/* <button
|
||||
{/* <button type="button"
|
||||
className="ml-2 underline"
|
||||
onClick={() =>
|
||||
pushModal('FunnelStepDetails', {
|
||||
@@ -234,6 +234,6 @@ export function Chart({
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { getChartColor, theme } from '@/utils/theme';
|
||||
import { useTheme } from 'next-themes';
|
||||
import React from 'react';
|
||||
import {
|
||||
Bar,
|
||||
BarChart,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { mergeDeepRight } from 'ramda';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { useInViewport } from 'react-in-viewport';
|
||||
|
||||
import { ReportAreaChart } from './area';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import { api } from '@/trpc/client';
|
||||
@@ -9,6 +8,7 @@ import { cn } from '@/utils/cn';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
import { isSameDay, isSameHour, isSameMonth } from 'date-fns';
|
||||
import { last } from 'ramda';
|
||||
import React, { useCallback } from 'react';
|
||||
import {
|
||||
Area,
|
||||
CartesianGrid,
|
||||
@@ -57,7 +57,7 @@ export function Chart({ data }: Props) {
|
||||
},
|
||||
{
|
||||
staleTime: 1000 * 60 * 10,
|
||||
}
|
||||
},
|
||||
);
|
||||
const { series, setVisibleSeries } = useVisibleSeries(data);
|
||||
const rechartData = useRechartDataModel(series);
|
||||
@@ -73,7 +73,7 @@ export function Chart({ data }: Props) {
|
||||
id: string,
|
||||
col1: string,
|
||||
col2: string,
|
||||
percentChange: number
|
||||
percentChange: number,
|
||||
) => (
|
||||
<linearGradient id={id} x1="0" y1="0" x2="100%" y2="0">
|
||||
<stop offset="0%" stopColor={col1} />
|
||||
@@ -177,29 +177,25 @@ export function Chart({ data }: Props) {
|
||||
x2="0"
|
||||
y2="1"
|
||||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.8}
|
||||
></stop>
|
||||
<stop offset="0%" stopColor={color} stopOpacity={0.8} />
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.1}
|
||||
></stop>
|
||||
/>
|
||||
</linearGradient>
|
||||
)}
|
||||
{gradientTwoColors(
|
||||
`hideAllButLastInterval_${serie.id}`,
|
||||
'rgba(0,0,0,0)',
|
||||
color,
|
||||
lastIntervalPercent
|
||||
lastIntervalPercent,
|
||||
)}
|
||||
{gradientTwoColors(
|
||||
`hideJustLastInterval_${serie.id}`,
|
||||
color,
|
||||
'rgba(0,0,0,0)',
|
||||
lastIntervalPercent
|
||||
lastIntervalPercent,
|
||||
)}
|
||||
</defs>
|
||||
<Line
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { theme } from '@/utils/theme';
|
||||
import { useMemo } from 'react';
|
||||
import WorldMap from 'react-svg-worldmap';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
|
||||
@@ -23,7 +23,7 @@ export function Chart({ data }: Props) {
|
||||
country: s.names[0]?.toLowerCase() ?? '',
|
||||
value: s.metrics[metric],
|
||||
})),
|
||||
[series, metric]
|
||||
[series, metric],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -21,7 +21,7 @@ export function Chart({ data }: Props) {
|
||||
<div
|
||||
className={cn(
|
||||
'grid grid-cols-1 gap-4',
|
||||
isEditMode && 'md:grid-cols-2 lg:grid-cols-3'
|
||||
isEditMode && 'md:grid-cols-2 lg:grid-cols-3',
|
||||
)}
|
||||
>
|
||||
{series.map((serie) => {
|
||||
|
||||
@@ -29,10 +29,10 @@ export function ReportMetricChart() {
|
||||
export function Loading() {
|
||||
return (
|
||||
<div className="flex h-[78px] flex-col justify-between p-4">
|
||||
<div className="h-3 w-1/2 animate-pulse rounded bg-def-200"></div>
|
||||
<div className="h-3 w-1/2 animate-pulse rounded bg-def-200" />
|
||||
<div className="row items-end justify-between">
|
||||
<div className="h-6 w-1/3 animate-pulse rounded bg-def-200"></div>
|
||||
<div className="h-3 w-1/5 animate-pulse rounded bg-def-200"></div>
|
||||
<div className="h-6 w-1/3 animate-pulse rounded bg-def-200" />
|
||||
<div className="h-3 w-1/5 animate-pulse rounded bg-def-200" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -9,8 +9,8 @@ import { Area, AreaChart } from 'recharts';
|
||||
import type { IChartMetric } from '@openpanel/validation';
|
||||
|
||||
import {
|
||||
getDiffIndicator,
|
||||
PreviousDiffIndicator,
|
||||
getDiffIndicator,
|
||||
} from '../common/previous-diff-indicator';
|
||||
import { SerieName } from '../common/serie-name';
|
||||
import { useReportChartContext } from '../context';
|
||||
@@ -54,7 +54,7 @@ export function MetricCard({
|
||||
previous?.state,
|
||||
'#6ee7b7', // green
|
||||
'#fda4af', // red
|
||||
'#93c5fd' // blue
|
||||
'#93c5fd', // blue
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -64,7 +64,7 @@ export function MetricCard({
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'pointer-events-none absolute -left-1 -right-1 bottom-0 top-0 z-0 opacity-50 transition-opacity duration-300 group-hover:opacity-100'
|
||||
'pointer-events-none absolute -left-1 -right-1 bottom-0 top-0 z-0 opacity-50 transition-opacity duration-300 group-hover:opacity-100',
|
||||
)}
|
||||
>
|
||||
<AutoSizer>
|
||||
|
||||
Reference in New Issue
Block a user