mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
feat(sales-stats): иконки на карточках во всех вкладках
Доделал душевный вид: карточки внутри вкладок (Триалы/Продажи/Продления/Допы/ Депозиты) тоже получили иконки в цветных чипах с тонами — единый стиль со сводкой (регистрации/триалы/конверсия/длительность, продажи/выручка/чек/топ-тариф, продления/%, допы/GB/устройства, пополнения/сумма/средний). Крупные суммы — без копеек.
This commit is contained in:
@@ -6,6 +6,13 @@ import type { SalesStatsParams } from '../../api/adminSalesStats';
|
||||
import { salesStatsApi } from '../../api/adminSalesStats';
|
||||
import { SALES_STATS } from '../../constants/salesStats';
|
||||
import { useCurrency } from '../../hooks/useCurrency';
|
||||
import {
|
||||
BanknotesIcon,
|
||||
CardIcon,
|
||||
DevicesIcon,
|
||||
PlusIcon,
|
||||
TrafficIcon,
|
||||
} from '../../components/icons';
|
||||
import { StatCard } from '../stats';
|
||||
|
||||
import { BreakdownList } from './BreakdownList';
|
||||
@@ -64,24 +71,32 @@ export function AddonsTab({ params }: AddonsTabProps) {
|
||||
<StatCard
|
||||
label={t('admin.salesStats.addons.totalPurchases')}
|
||||
value={data.total_purchases}
|
||||
icon={<PlusIcon className="h-5 w-5" />}
|
||||
tone="accent"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.addons.totalGb')}
|
||||
value={`${data.total_gb_purchased} GB`}
|
||||
icon={<TrafficIcon className="h-5 w-5" />}
|
||||
tone="neutral"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.addons.revenue')}
|
||||
value={formatWithCurrency(data.addon_revenue_kopeks / SALES_STATS.KOPEKS_DIVISOR)}
|
||||
valueClassName="text-success-400"
|
||||
value={formatWithCurrency(data.addon_revenue_kopeks / SALES_STATS.KOPEKS_DIVISOR, 0)}
|
||||
icon={<BanknotesIcon className="h-5 w-5" />}
|
||||
tone="success"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.addons.devicePurchases')}
|
||||
value={data.device_purchases}
|
||||
icon={<DevicesIcon className="h-5 w-5" />}
|
||||
tone="accent"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.addons.deviceRevenue')}
|
||||
value={formatWithCurrency(data.device_revenue_kopeks / SALES_STATS.KOPEKS_DIVISOR)}
|
||||
valueClassName="text-success-400"
|
||||
value={formatWithCurrency(data.device_revenue_kopeks / SALES_STATS.KOPEKS_DIVISOR, 0)}
|
||||
icon={<CardIcon className="h-5 w-5" />}
|
||||
tone="success"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { salesStatsApi } from '../../api/adminSalesStats';
|
||||
import { METHOD_LABELS } from '../../constants/paymentMethods';
|
||||
import { SALES_STATS } from '../../constants/salesStats';
|
||||
import { useCurrency } from '../../hooks/useCurrency';
|
||||
import { BanknotesIcon, CardIcon, WalletIcon } from '../../components/icons';
|
||||
import { StatCard } from '../stats';
|
||||
|
||||
import PaymentMethodIcon from '../PaymentMethodIcon';
|
||||
@@ -82,15 +83,20 @@ export function DepositsTab({ params }: DepositsTabProps) {
|
||||
<StatCard
|
||||
label={t('admin.salesStats.deposits.totalDeposits')}
|
||||
value={data.total_deposits}
|
||||
icon={<WalletIcon className="h-5 w-5" />}
|
||||
tone="accent"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.deposits.totalAmount')}
|
||||
value={formatWithCurrency(data.total_amount_kopeks / SALES_STATS.KOPEKS_DIVISOR)}
|
||||
valueClassName="text-success-400"
|
||||
value={formatWithCurrency(data.total_amount_kopeks / SALES_STATS.KOPEKS_DIVISOR, 0)}
|
||||
icon={<BanknotesIcon className="h-5 w-5" />}
|
||||
tone="success"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.deposits.avgDeposit')}
|
||||
value={formatWithCurrency(data.avg_deposit_kopeks / SALES_STATS.KOPEKS_DIVISOR)}
|
||||
icon={<CardIcon className="h-5 w-5" />}
|
||||
tone="neutral"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { SalesStatsParams } from '../../api/adminSalesStats';
|
||||
import { salesStatsApi } from '../../api/adminSalesStats';
|
||||
import { SALES_STATS } from '../../constants/salesStats';
|
||||
import { useCurrency } from '../../hooks/useCurrency';
|
||||
import { BanknotesIcon, PercentIcon, RepeatIcon } from '../../components/icons';
|
||||
import { StatCard } from '../stats';
|
||||
import { TREND_STYLES } from '../stats/constants';
|
||||
|
||||
@@ -49,16 +50,23 @@ export function RenewalsTab({ params }: RenewalsTabProps) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
||||
<StatCard label={t('admin.salesStats.renewals.total')} value={data.total_renewals} />
|
||||
<StatCard
|
||||
label={t('admin.salesStats.renewals.total')}
|
||||
value={data.total_renewals}
|
||||
icon={<RepeatIcon className="h-5 w-5" />}
|
||||
tone="success"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.renewals.rate')}
|
||||
value={`${data.renewal_rate}%`}
|
||||
valueClassName="text-success-400"
|
||||
icon={<PercentIcon className="h-5 w-5" />}
|
||||
tone="accent"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.renewals.revenue')}
|
||||
value={formatWithCurrency(data.total_revenue_kopeks / SALES_STATS.KOPEKS_DIVISOR)}
|
||||
valueClassName="text-success-400"
|
||||
value={formatWithCurrency(data.total_revenue_kopeks / SALES_STATS.KOPEKS_DIVISOR, 0)}
|
||||
icon={<BanknotesIcon className="h-5 w-5" />}
|
||||
tone="success"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { SalesStatsParams } from '../../api/adminSalesStats';
|
||||
import { salesStatsApi } from '../../api/adminSalesStats';
|
||||
import { SALES_STATS } from '../../constants/salesStats';
|
||||
import { useCurrency } from '../../hooks/useCurrency';
|
||||
import { BanknotesIcon, CardIcon, TicketIcon, TrophyIcon } from '../../components/icons';
|
||||
import { StatCard } from '../stats';
|
||||
|
||||
import { BreakdownList } from './BreakdownList';
|
||||
@@ -68,18 +69,30 @@ export function SalesTab({ params }: SalesTabProps) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
|
||||
<StatCard label={t('admin.salesStats.sales.totalSales')} value={data.total_sales} />
|
||||
<StatCard
|
||||
label={t('admin.salesStats.sales.totalSales')}
|
||||
value={data.total_sales}
|
||||
icon={<TicketIcon className="h-5 w-5" />}
|
||||
tone="accent"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.sales.totalRevenue')}
|
||||
value={formatWithCurrency(data.total_revenue_kopeks / SALES_STATS.KOPEKS_DIVISOR)}
|
||||
valueClassName="text-success-400"
|
||||
value={formatWithCurrency(data.total_revenue_kopeks / SALES_STATS.KOPEKS_DIVISOR, 0)}
|
||||
icon={<BanknotesIcon className="h-5 w-5" />}
|
||||
tone="success"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.sales.avgOrder')}
|
||||
value={formatWithCurrency(data.avg_order_kopeks / SALES_STATS.KOPEKS_DIVISOR)}
|
||||
valueClassName="text-success-400"
|
||||
icon={<CardIcon className="h-5 w-5" />}
|
||||
tone="success"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.sales.topTariff')}
|
||||
value={data.top_tariff_name}
|
||||
icon={<TrophyIcon className="h-5 w-5" />}
|
||||
tone="warning"
|
||||
/>
|
||||
<StatCard label={t('admin.salesStats.sales.topTariff')} value={data.top_tariff_name} />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import type { SalesStatsParams } from '../../api/adminSalesStats';
|
||||
import { salesStatsApi } from '../../api/adminSalesStats';
|
||||
import { SALES_STATS } from '../../constants/salesStats';
|
||||
import { ClockIcon, GiftIcon, PercentIcon, UserPlusIcon } from '../../components/icons';
|
||||
import { StatCard } from '../stats';
|
||||
|
||||
import { DonutChart } from './DonutChart';
|
||||
@@ -64,16 +65,26 @@ export function TrialsTab({ params }: TrialsTabProps) {
|
||||
<StatCard
|
||||
label={t('admin.salesStats.trials.totalRegistrations')}
|
||||
value={data.total_registrations}
|
||||
icon={<UserPlusIcon className="h-5 w-5" />}
|
||||
tone="accent"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.trials.total')}
|
||||
value={data.total_trials}
|
||||
icon={<GiftIcon className="h-5 w-5" />}
|
||||
tone="neutral"
|
||||
/>
|
||||
<StatCard label={t('admin.salesStats.trials.total')} value={data.total_trials} />
|
||||
<StatCard
|
||||
label={t('admin.salesStats.trials.conversion')}
|
||||
value={`${data.conversion_rate}%`}
|
||||
valueClassName="text-success-400"
|
||||
icon={<PercentIcon className="h-5 w-5" />}
|
||||
tone="success"
|
||||
/>
|
||||
<StatCard
|
||||
label={t('admin.salesStats.trials.avgDuration')}
|
||||
value={`${data.avg_trial_duration_days} ${t('admin.trafficUsage.days')}`}
|
||||
icon={<ClockIcon className="h-5 w-5" />}
|
||||
tone="neutral"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user