mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
- Move shared chart components (DailyChart, PeriodComparison, StatCard) to src/components/stats/ with configurable label props - Create shared types for chart data decoupled from partner API - Add campaign chart data API client with deposits/spending split - Enhance AdminCampaignStats with daily trends chart, period comparison, top registrations, and deposit/spending stat cards - Add useChartColors hook with SSR guard and theme-aware CSS variable parsing - Add cross-platform clipboard utility with execCommand fallback for Telegram WebView - Add i18n keys for chart analytics across all 4 locales (en, ru, zh, fa) - Responsive fixes: truncation for long names/values, responsive text sizing, touch-friendly copy buttons
302 lines
8.2 KiB
TypeScript
302 lines
8.2 KiB
TypeScript
import apiClient from './client';
|
|
|
|
// ==================== User-facing types ====================
|
|
|
|
export interface PartnerApplicationInfo {
|
|
id: number;
|
|
status: string;
|
|
company_name: string | null;
|
|
website_url: string | null;
|
|
telegram_channel: string | null;
|
|
description: string | null;
|
|
expected_monthly_referrals: number | null;
|
|
desired_commission_percent: number | null;
|
|
admin_comment: string | null;
|
|
approved_commission_percent: number | null;
|
|
created_at: string;
|
|
processed_at: string | null;
|
|
}
|
|
|
|
export interface PartnerCampaignInfo {
|
|
id: number;
|
|
name: string;
|
|
start_parameter: string;
|
|
bonus_type: string;
|
|
balance_bonus_kopeks: number;
|
|
subscription_duration_days: number | null;
|
|
subscription_traffic_gb: number | null;
|
|
deep_link: string | null;
|
|
web_link: string | null;
|
|
// Per-campaign statistics
|
|
registrations_count: number;
|
|
referrals_count: number;
|
|
earnings_kopeks: number;
|
|
}
|
|
|
|
export interface PartnerStatusResponse {
|
|
partner_status: string;
|
|
commission_percent: number | null;
|
|
latest_application: PartnerApplicationInfo | null;
|
|
campaigns: PartnerCampaignInfo[];
|
|
}
|
|
|
|
export interface PartnerApplicationRequest {
|
|
company_name?: string;
|
|
website_url?: string;
|
|
telegram_channel?: string;
|
|
description?: string;
|
|
expected_monthly_referrals?: number;
|
|
desired_commission_percent?: number;
|
|
}
|
|
|
|
// ==================== Campaign detailed stats types ====================
|
|
|
|
export interface DailyStatItem {
|
|
date: string;
|
|
referrals_count: number;
|
|
earnings_kopeks: number;
|
|
}
|
|
|
|
export interface PeriodStats {
|
|
days: number;
|
|
referrals_count: number;
|
|
earnings_kopeks: number;
|
|
}
|
|
|
|
export interface PeriodChange {
|
|
absolute: number;
|
|
percent: number;
|
|
trend: 'up' | 'down' | 'stable';
|
|
}
|
|
|
|
export interface PeriodComparison {
|
|
current: PeriodStats;
|
|
previous: PeriodStats;
|
|
referrals_change: PeriodChange;
|
|
earnings_change: PeriodChange;
|
|
}
|
|
|
|
export interface CampaignReferralItem {
|
|
id: number;
|
|
full_name: string;
|
|
created_at: string;
|
|
has_paid: boolean;
|
|
is_active: boolean;
|
|
total_earnings_kopeks: number;
|
|
}
|
|
|
|
export interface PartnerCampaignDetailedStats {
|
|
campaign_id: number;
|
|
campaign_name: string;
|
|
registrations_count: number;
|
|
referrals_count: number;
|
|
earnings_kopeks: number;
|
|
conversion_rate: number;
|
|
earnings_today: number;
|
|
earnings_week: number;
|
|
earnings_month: number;
|
|
daily_stats: DailyStatItem[];
|
|
period_comparison: PeriodComparison;
|
|
top_referrals: CampaignReferralItem[];
|
|
}
|
|
|
|
// ==================== Admin-facing types ====================
|
|
|
|
export interface AdminPartnerApplicationItem {
|
|
id: number;
|
|
user_id: number;
|
|
username: string | null;
|
|
first_name: string | null;
|
|
telegram_id: number | null;
|
|
company_name: string | null;
|
|
website_url: string | null;
|
|
telegram_channel: string | null;
|
|
description: string | null;
|
|
expected_monthly_referrals: number | null;
|
|
desired_commission_percent: number | null;
|
|
status: string;
|
|
admin_comment: string | null;
|
|
approved_commission_percent: number | null;
|
|
created_at: string;
|
|
processed_at: string | null;
|
|
}
|
|
|
|
export interface AdminPartnerApplicationsResponse {
|
|
items: AdminPartnerApplicationItem[];
|
|
total: number;
|
|
}
|
|
|
|
export interface AdminPartnerItem {
|
|
user_id: number;
|
|
username: string | null;
|
|
first_name: string | null;
|
|
telegram_id: number | null;
|
|
commission_percent: number | null;
|
|
total_referrals: number;
|
|
total_earnings_kopeks: number;
|
|
balance_kopeks: number;
|
|
partner_status: string;
|
|
created_at: string;
|
|
}
|
|
|
|
export interface AdminPartnerListResponse {
|
|
items: AdminPartnerItem[];
|
|
total: number;
|
|
}
|
|
|
|
export interface AdminPartnerDetailResponse {
|
|
user_id: number;
|
|
username: string | null;
|
|
first_name: string | null;
|
|
telegram_id: number | null;
|
|
commission_percent: number | null;
|
|
partner_status: string;
|
|
balance_kopeks: number;
|
|
total_referrals: number;
|
|
paid_referrals: number;
|
|
active_referrals: number;
|
|
earnings_all_time: number;
|
|
earnings_today: number;
|
|
earnings_week: number;
|
|
earnings_month: number;
|
|
conversion_to_paid: number;
|
|
campaigns: {
|
|
id: number;
|
|
name: string;
|
|
start_parameter: string;
|
|
is_active: boolean;
|
|
registrations_count: number;
|
|
referrals_count: number;
|
|
earnings_kopeks: number;
|
|
}[];
|
|
created_at: string;
|
|
}
|
|
|
|
export interface PartnerStats {
|
|
total_partners: number;
|
|
pending_applications: number;
|
|
total_referrals: number;
|
|
total_earnings_kopeks: number;
|
|
}
|
|
|
|
// ==================== Partner Settings types ====================
|
|
|
|
export interface PartnerSettings {
|
|
withdrawal_enabled: boolean;
|
|
withdrawal_min_amount_kopeks: number;
|
|
withdrawal_cooldown_days: number;
|
|
withdrawal_requisites_text: string;
|
|
partner_section_visible: boolean;
|
|
referral_program_enabled: boolean;
|
|
}
|
|
|
|
export interface PartnerSettingsUpdate {
|
|
withdrawal_enabled?: boolean;
|
|
withdrawal_min_amount_kopeks?: number;
|
|
withdrawal_cooldown_days?: number;
|
|
withdrawal_requisites_text?: string;
|
|
partner_section_visible?: boolean;
|
|
referral_program_enabled?: boolean;
|
|
}
|
|
|
|
export const partnerApi = {
|
|
// User endpoints
|
|
getStatus: async (): Promise<PartnerStatusResponse> => {
|
|
const response = await apiClient.get<PartnerStatusResponse>('/cabinet/referral/partner/status');
|
|
return response.data;
|
|
},
|
|
|
|
apply: async (data: PartnerApplicationRequest): Promise<PartnerApplicationInfo> => {
|
|
const response = await apiClient.post<PartnerApplicationInfo>(
|
|
'/cabinet/referral/partner/apply',
|
|
data,
|
|
);
|
|
return response.data;
|
|
},
|
|
|
|
getCampaignStats: async (campaignId: number): Promise<PartnerCampaignDetailedStats> => {
|
|
const response = await apiClient.get<PartnerCampaignDetailedStats>(
|
|
`/cabinet/referral/partner/campaigns/${campaignId}/stats`,
|
|
);
|
|
return response.data;
|
|
},
|
|
|
|
// Admin endpoints
|
|
getStats: async (): Promise<PartnerStats> => {
|
|
const response = await apiClient.get<PartnerStats>('/cabinet/admin/partners/stats');
|
|
return response.data;
|
|
},
|
|
|
|
getApplications: async (params?: {
|
|
status?: string;
|
|
offset?: number;
|
|
limit?: number;
|
|
}): Promise<AdminPartnerApplicationsResponse> => {
|
|
const response = await apiClient.get<AdminPartnerApplicationsResponse>(
|
|
'/cabinet/admin/partners/applications',
|
|
{ params },
|
|
);
|
|
return response.data;
|
|
},
|
|
|
|
approveApplication: async (
|
|
applicationId: number,
|
|
data: { commission_percent: number; comment?: string },
|
|
): Promise<void> => {
|
|
await apiClient.post(`/cabinet/admin/partners/applications/${applicationId}/approve`, data);
|
|
},
|
|
|
|
rejectApplication: async (applicationId: number, data: { comment?: string }): Promise<void> => {
|
|
await apiClient.post(`/cabinet/admin/partners/applications/${applicationId}/reject`, data);
|
|
},
|
|
|
|
getPartners: async (params?: {
|
|
offset?: number;
|
|
limit?: number;
|
|
}): Promise<AdminPartnerListResponse> => {
|
|
const response = await apiClient.get<AdminPartnerListResponse>('/cabinet/admin/partners', {
|
|
params,
|
|
});
|
|
return response.data;
|
|
},
|
|
|
|
getPartnerDetail: async (userId: number): Promise<AdminPartnerDetailResponse> => {
|
|
const response = await apiClient.get<AdminPartnerDetailResponse>(
|
|
`/cabinet/admin/partners/${userId}`,
|
|
);
|
|
return response.data;
|
|
},
|
|
|
|
updateCommission: async (userId: number, commissionPercent: number): Promise<void> => {
|
|
await apiClient.patch(`/cabinet/admin/partners/${userId}/commission`, {
|
|
commission_percent: commissionPercent,
|
|
});
|
|
},
|
|
|
|
revokePartner: async (userId: number): Promise<void> => {
|
|
await apiClient.post(`/cabinet/admin/partners/${userId}/revoke`);
|
|
},
|
|
|
|
assignCampaign: async (userId: number, campaignId: number): Promise<void> => {
|
|
await apiClient.post(`/cabinet/admin/partners/${userId}/campaigns/${campaignId}/assign`);
|
|
},
|
|
|
|
unassignCampaign: async (userId: number, campaignId: number): Promise<void> => {
|
|
await apiClient.post(`/cabinet/admin/partners/${userId}/campaigns/${campaignId}/unassign`);
|
|
},
|
|
|
|
// Settings
|
|
getPartnerSettings: async (): Promise<PartnerSettings> => {
|
|
const response = await apiClient.get<PartnerSettings>('/cabinet/admin/partners/settings');
|
|
return response.data;
|
|
},
|
|
|
|
updatePartnerSettings: async (data: PartnerSettingsUpdate): Promise<PartnerSettings> => {
|
|
const response = await apiClient.patch<PartnerSettings>(
|
|
'/cabinet/admin/partners/settings',
|
|
data,
|
|
);
|
|
return response.data;
|
|
},
|
|
};
|