mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-29 18:13:47 +00:00
feat: display per-campaign stats on partner detail page
- Add registrations_count, referrals_count, earnings_kopeks to campaign type - Show per-campaign stats grid (registrations, referrals, earnings) under each campaign card - Use conditional coloring for zero earnings (neutral instead of green)
This commit is contained in:
@@ -105,7 +105,15 @@ export interface AdminPartnerDetailResponse {
|
|||||||
earnings_week: number;
|
earnings_week: number;
|
||||||
earnings_month: number;
|
earnings_month: number;
|
||||||
conversion_to_paid: number;
|
conversion_to_paid: number;
|
||||||
campaigns: { id: number; name: string; start_parameter: string; is_active: boolean }[];
|
campaigns: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
start_parameter: string;
|
||||||
|
is_active: boolean;
|
||||||
|
registrations_count: number;
|
||||||
|
referrals_count: number;
|
||||||
|
earnings_kopeks: number;
|
||||||
|
}[];
|
||||||
created_at: string;
|
created_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -232,46 +232,76 @@ export default function AdminPartnerDetail() {
|
|||||||
{partner.campaigns.map((campaign) => (
|
{partner.campaigns.map((campaign) => (
|
||||||
<div
|
<div
|
||||||
key={campaign.id}
|
key={campaign.id}
|
||||||
className={`flex items-center justify-between rounded-lg bg-dark-700/50 p-3 ${
|
className={`rounded-lg bg-dark-700/50 p-3 ${
|
||||||
!campaign.is_active ? 'opacity-60' : ''
|
!campaign.is_active ? 'opacity-60' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="flex items-center justify-between">
|
||||||
<div className="font-medium text-dark-100">{campaign.name}</div>
|
<div className="min-w-0 flex-1">
|
||||||
<div className="font-mono text-xs text-dark-500">
|
<div className="font-medium text-dark-100">{campaign.name}</div>
|
||||||
?start={campaign.start_parameter}
|
<div className="font-mono text-xs text-dark-500">
|
||||||
|
?start={campaign.start_parameter}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{campaign.is_active ? (
|
||||||
|
<span className="rounded bg-success-500/20 px-2 py-0.5 text-xs text-success-400">
|
||||||
|
{t('admin.partnerDetail.campaigns.active')}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="rounded bg-dark-600 px-2 py-0.5 text-xs text-dark-400">
|
||||||
|
{t('admin.partnerDetail.campaigns.inactive')}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={() => unassignMutation.mutate(campaign.id)}
|
||||||
|
disabled={unassignMutation.isPending}
|
||||||
|
className="rounded p-1 text-dark-500 transition-colors hover:bg-error-500/10 hover:text-error-400"
|
||||||
|
title={t('admin.partnerDetail.campaigns.unassign')}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="h-4 w-4"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth={2}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
d="M6 18L18 6M6 6l12 12"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="mt-2 grid grid-cols-3 gap-2 border-t border-dark-600/50 pt-2">
|
||||||
{campaign.is_active ? (
|
<div className="text-center">
|
||||||
<span className="rounded bg-success-500/20 px-2 py-0.5 text-xs text-success-400">
|
<div className="text-sm font-medium text-dark-200">
|
||||||
{t('admin.partnerDetail.campaigns.active')}
|
{campaign.registrations_count}
|
||||||
</span>
|
</div>
|
||||||
) : (
|
<div className="text-[10px] text-dark-500">
|
||||||
<span className="rounded bg-dark-600 px-2 py-0.5 text-xs text-dark-400">
|
{t('admin.partnerDetail.campaigns.registrations', 'Регистрации')}
|
||||||
{t('admin.partnerDetail.campaigns.inactive')}
|
</div>
|
||||||
</span>
|
</div>
|
||||||
)}
|
<div className="text-center">
|
||||||
<button
|
<div className="text-sm font-medium text-dark-200">
|
||||||
onClick={() => unassignMutation.mutate(campaign.id)}
|
{campaign.referrals_count}
|
||||||
disabled={unassignMutation.isPending}
|
</div>
|
||||||
className="rounded p-1 text-dark-500 transition-colors hover:bg-error-500/10 hover:text-error-400"
|
<div className="text-[10px] text-dark-500">
|
||||||
title={t('admin.partnerDetail.campaigns.unassign')}
|
{t('admin.partnerDetail.campaigns.referrals', 'Рефералы')}
|
||||||
>
|
</div>
|
||||||
<svg
|
</div>
|
||||||
className="h-4 w-4"
|
<div className="text-center">
|
||||||
fill="none"
|
<div
|
||||||
viewBox="0 0 24 24"
|
className={`text-sm font-medium ${campaign.earnings_kopeks > 0 ? 'text-success-400' : 'text-dark-400'}`}
|
||||||
stroke="currentColor"
|
|
||||||
strokeWidth={2}
|
|
||||||
>
|
>
|
||||||
<path
|
{formatWithCurrency(campaign.earnings_kopeks / 100)}
|
||||||
strokeLinecap="round"
|
</div>
|
||||||
strokeLinejoin="round"
|
<div className="text-[10px] text-dark-500">
|
||||||
d="M6 18L18 6M6 6l12 12"
|
{t('admin.partnerDetail.campaigns.earnings', 'Доход')}
|
||||||
/>
|
</div>
|
||||||
</svg>
|
</div>
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user