import { FC, useCallback, useMemo, useState } from 'react'; import { Integration } from '@prisma/client'; import useSWR from 'swr'; import { useFetch } from '@gitroom/helpers/utils/custom.fetch'; import { ChartSocial } from '@gitroom/frontend/components/analytics/chart-social'; import { LoadingComponent } from '@gitroom/frontend/components/layout/loading'; import { useT } from '@gitroom/react/translation/get.transation.service.client'; interface AnalyticsDataItem { label: string; data: Array<{ total: number; date: string }>; average?: boolean; percentageChange?: number; } const TrendIndicator: FC<{ value: number; average?: boolean }> = ({ value, average, }) => { if (value === 0) return null; const isPositive = value > 0; const displayValue = Math.abs(value).toFixed(1); return (
{displayValue} {average ? 'pp' : '%'}
); }; const AnalyticsCard: FC<{ item: AnalyticsDataItem; total: string | number; index: number; }> = ({ item, total, index }) => { const colorVariants = ['purple', 'green', 'blue'] as const; const color = colorVariants[index % colorVariants.length]; const hasDataPoints = item.data.length >= 1; return (
{/* Header */}
{item.label}
{item.percentageChange !== undefined && ( )}
{/* Content */} {hasDataPoints ? ( <> {/* Chart */}
{/* Value */}
{total}
) : ( /* Single value display */
{total}
)}
); }; const EmptyState: FC<{ onRefresh: () => void }> = ({ onRefresh }) => { const t = useT(); return (

{t( 'this_channel_needs_to_be_refreshed', 'This channel needs to be refreshed to display analytics' )}

); }; export const RenderAnalytics: FC<{ integration: Integration; date: number; }> = (props) => { const { integration, date } = props; const [loading, setLoading] = useState(true); const fetch = useFetch(); const load = useCallback(async () => { setLoading(true); const load = ( await fetch(`/analytics/${integration.id}?date=${date}`) ).json(); setLoading(false); return load; }, [integration, date]); const { data } = useSWR(`/analytics-${integration?.id}-${date}`, load, { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, revalidateOnReconnect: false, revalidateIfStale: false, refreshWhenOffline: false, revalidateOnMount: true, }); const refreshChannel = useCallback( ( integrationData: Integration & { identifier: string; } ) => async () => { const { url } = await ( await fetch( `/integrations/social/${integrationData.identifier}?refresh=${integrationData.internalId}`, { method: 'GET', } ) ).json(); window.location.href = url; }, [] ); const t = useT(); const totals = useMemo(() => { return data?.map((p: AnalyticsDataItem) => { const value = (p?.data.reduce((acc: number, curr: { total: number }) => acc + curr.total, 0) || 0) / (p.average ? p.data.length : 1); if (p.average) { return value.toFixed(2) + '%'; } return new Intl.NumberFormat().format(Math.round(value)); }); }, [data]); if (loading) { return (
); } return (
{data?.length === 0 && ( )} {data?.map((item: AnalyticsDataItem, index: number) => ( ))}
); };