mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
feat: add daily traffic & device purchase chart to addons stats
Add DualAreaChart to addons tab showing daily traffic purchases vs device purchases with date-union merge. Add daily_devices field to AddonsStats type and i18n keys for all 4 locales.
This commit is contained in:
@@ -119,6 +119,11 @@ export interface DailyAddonItem {
|
||||
total_gb: number;
|
||||
}
|
||||
|
||||
export interface DailyDeviceItem {
|
||||
date: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface AddonsStats {
|
||||
total_purchases: number;
|
||||
total_gb_purchased: number;
|
||||
@@ -127,6 +132,7 @@ export interface AddonsStats {
|
||||
device_revenue_kopeks: number;
|
||||
by_package: AddonByPackageItem[];
|
||||
daily: DailyAddonItem[];
|
||||
daily_devices: DailyDeviceItem[];
|
||||
}
|
||||
|
||||
// ============ Deposits ============
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -7,7 +8,7 @@ import { SALES_STATS } from '../../constants/salesStats';
|
||||
import { useCurrency } from '../../hooks/useCurrency';
|
||||
import { StatCard } from '../stats';
|
||||
|
||||
import { SimpleAreaChart } from './SimpleAreaChart';
|
||||
import { DualAreaChart } from './DualAreaChart';
|
||||
import { SimpleBarChart } from './SimpleBarChart';
|
||||
|
||||
interface AddonsTabProps {
|
||||
@@ -24,6 +25,18 @@ export function AddonsTab({ params }: AddonsTabProps) {
|
||||
staleTime: SALES_STATS.STALE_TIME,
|
||||
});
|
||||
|
||||
const dailyChartData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
const trafficByDate = new Map(data.daily.map((d) => [d.date, d.count]));
|
||||
const deviceByDate = new Map(data.daily_devices.map((d) => [d.date, d.count]));
|
||||
const allDates = Array.from(new Set([...trafficByDate.keys(), ...deviceByDate.keys()])).sort();
|
||||
return allDates.map((date) => ({
|
||||
date,
|
||||
series1: trafficByDate.get(date) ?? 0,
|
||||
series2: deviceByDate.get(date) ?? 0,
|
||||
}));
|
||||
}, [data]);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="animate-pulse space-y-4">
|
||||
@@ -43,11 +56,6 @@ export function AddonsTab({ params }: AddonsTabProps) {
|
||||
value: item.count,
|
||||
}));
|
||||
|
||||
const dailyData = data.daily.map((item) => ({
|
||||
date: item.date,
|
||||
value: item.count,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5">
|
||||
@@ -77,12 +85,14 @@ export function AddonsTab({ params }: AddonsTabProps) {
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||
<SimpleBarChart data={packageBarData} title={t('admin.salesStats.addons.byPackage')} />
|
||||
<SimpleAreaChart
|
||||
data={dailyData}
|
||||
<DualAreaChart
|
||||
data={dailyChartData}
|
||||
title={t('admin.salesStats.addons.dailyChart')}
|
||||
chartId="addons-daily"
|
||||
valueLabel={t('admin.salesStats.addons.purchases')}
|
||||
color={SALES_STATS.BAR_COLORS[5]}
|
||||
series1Label={t('admin.salesStats.addons.trafficPurchases')}
|
||||
series2Label={t('admin.salesStats.addons.devicePurchasesDaily')}
|
||||
series1Color={SALES_STATS.BAR_COLORS[5]}
|
||||
series2Color={SALES_STATS.BAR_COLORS[3]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1140,8 +1140,10 @@
|
||||
"revenue": "Revenue",
|
||||
"devicePurchases": "Device Purchases",
|
||||
"deviceRevenue": "Device Revenue",
|
||||
"trafficPurchases": "Traffic",
|
||||
"devicePurchasesDaily": "Devices",
|
||||
"byPackage": "By Package Size",
|
||||
"dailyChart": "Daily Purchases",
|
||||
"dailyChart": "Daily Add-on Purchases",
|
||||
"purchases": "Purchases"
|
||||
},
|
||||
"deposits": {
|
||||
|
||||
@@ -963,8 +963,10 @@
|
||||
"revenue": "درآمد",
|
||||
"devicePurchases": "خرید دستگاه",
|
||||
"deviceRevenue": "درآمد دستگاه",
|
||||
"trafficPurchases": "ترافیک",
|
||||
"devicePurchasesDaily": "دستگاه",
|
||||
"byPackage": "بر اساس بسته",
|
||||
"dailyChart": "خرید روزانه",
|
||||
"dailyChart": "خرید روزانه خدمات اضافی",
|
||||
"purchases": "خرید"
|
||||
},
|
||||
"deposits": {
|
||||
|
||||
@@ -1161,8 +1161,10 @@
|
||||
"revenue": "Доход",
|
||||
"devicePurchases": "Покупки устройств",
|
||||
"deviceRevenue": "Доход от устройств",
|
||||
"trafficPurchases": "Трафик",
|
||||
"devicePurchasesDaily": "Устройства",
|
||||
"byPackage": "По размеру пакета",
|
||||
"dailyChart": "Покупки по дням",
|
||||
"dailyChart": "Покупки доп. услуг по дням",
|
||||
"purchases": "Покупки"
|
||||
},
|
||||
"deposits": {
|
||||
|
||||
@@ -963,8 +963,10 @@
|
||||
"revenue": "收入",
|
||||
"devicePurchases": "设备购买",
|
||||
"deviceRevenue": "设备收入",
|
||||
"trafficPurchases": "流量",
|
||||
"devicePurchasesDaily": "设备",
|
||||
"byPackage": "按套餐大小",
|
||||
"dailyChart": "每日购买",
|
||||
"dailyChart": "每日附加服务购买",
|
||||
"purchases": "购买"
|
||||
},
|
||||
"deposits": {
|
||||
|
||||
Reference in New Issue
Block a user