feat: add referral network graph visualization page

Interactive Sigma.js + graphology graph with ForceAtlas2 web worker
layout, campaign/user node coloring, filters via nodeReducer pattern,
search highlighting, user/campaign detail side panels, and 4-locale
translations. Dependencies: sigma v3, graphology, graphology-layout-forceatlas2.
This commit is contained in:
Fringg
2026-03-19 07:56:01 +03:00
parent 84f0e4e9b4
commit 235eaec85f
23 changed files with 2126 additions and 8 deletions

View File

@@ -0,0 +1,48 @@
import { useTranslation } from 'react-i18next';
import type { NetworkGraphData } from '@/types/referralNetwork';
import { formatKopeksToRubles } from '../utils';
interface NetworkStatsProps {
data: NetworkGraphData;
className?: string;
}
export function NetworkStats({ data, className }: NetworkStatsProps) {
const { t } = useTranslation();
const stats = [
{
label: t('admin.referralNetwork.stats.totalUsers'),
value: data.total_users.toLocaleString(),
},
{
label: t('admin.referralNetwork.stats.totalReferrers'),
value: data.total_referrers.toLocaleString(),
},
{
label: t('admin.referralNetwork.stats.totalCampaigns'),
value: data.total_campaigns.toLocaleString(),
},
{
label: t('admin.referralNetwork.stats.totalEarnings'),
value: `${formatKopeksToRubles(data.total_earnings_kopeks)}`,
},
];
return (
<div
className={`rounded-xl border border-dark-700/50 bg-dark-900/80 p-3 backdrop-blur-md ${className ?? ''}`}
>
<div className="grid grid-cols-2 gap-3">
{stats.map((stat) => (
<div key={stat.label}>
<p className="text-[10px] font-medium uppercase tracking-wider text-dark-500">
{stat.label}
</p>
<p className="font-mono text-sm font-semibold text-dark-100">{stat.value}</p>
</div>
))}
</div>
</div>
);
}