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,102 @@
export interface NetworkUserNode {
id: number;
tg_id: number | null;
username: string | null;
email: string | null;
display_name: string;
is_partner: boolean;
referrer_id: number | null;
campaign_id: number | null;
direct_referrals: number;
total_branch_users: number;
branch_revenue_kopeks: number;
personal_revenue_kopeks: number;
personal_spent_kopeks: number;
subscription_name: string | null;
subscription_end: string | null;
registered_at: string | null;
}
export interface NetworkCampaignNode {
id: number;
name: string;
start_parameter: string;
is_active: boolean;
direct_users: number;
total_network_users: number;
total_revenue_kopeks: number;
conversion_rate: number;
avg_check_kopeks: number;
top_referrers: Array<{
user_id: number;
username: string | null;
referral_count: number;
}>;
}
export interface NetworkEdge {
source: string;
target: string;
type: 'referral' | 'campaign';
}
export interface NetworkGraphData {
users: NetworkUserNode[];
campaigns: NetworkCampaignNode[];
edges: NetworkEdge[];
total_users: number;
total_referrers: number;
total_campaigns: number;
total_earnings_kopeks: number;
}
export interface NetworkUserDetail {
id: number;
tg_id: number | null;
username: string | null;
email: string | null;
display_name: string;
is_partner: boolean;
referrer_id: number | null;
referrer_display_name: string | null;
campaign_id: number | null;
campaign_name: string | null;
direct_referrals: number;
total_branch_users: number;
branch_revenue_kopeks: number;
personal_revenue_kopeks: number;
personal_spent_kopeks: number;
subscription_name: string | null;
subscription_end: string | null;
registered_at: string | null;
}
export interface NetworkCampaignDetail {
id: number;
name: string;
start_parameter: string;
is_active: boolean;
direct_users: number;
total_network_users: number;
total_revenue_kopeks: number;
conversion_rate: number;
avg_check_kopeks: number;
top_referrers: Array<{
user_id: number;
username: string | null;
referral_count: number;
}>;
}
export interface NetworkSearchResult {
users: NetworkUserNode[];
campaigns: NetworkCampaignNode[];
}
export type SelectedNode = { type: 'user'; id: number } | { type: 'campaign'; id: number } | null;
export interface NetworkFilters {
campaigns: number[];
partnersOnly: boolean;
minReferrals: number;
}