+
}
+ tone="accent"
+ loading={!initialLoaded && loading}
+ />
+
+ {/* Filter chips */}
+
+ {FILTERS.map(({ key }) => (
+
+ ))}
+
+
+ {/* Timeline */}
+ {!initialLoaded && loading ? (
+
+ ) : items.length === 0 ? (
+
+
+
{t('admin.users.detail.activity.empty')}
+
+ ) : (
+
+ {items.map((item, index) => {
+ const visual = TYPE_VISUALS[item.type] || FALLBACK_VISUAL;
+ const Icon = visual.icon;
+ const typeLabel =
+ t(`admin.users.detail.activity.types.${item.type}`, { defaultValue: '' }) ||
+ item.type;
+ const isLast = index === items.length - 1;
+
+ return (
+
+ {/* Icon column + connecting line */}
+
+
+ {/* Content */}
+
+
+
+ {typeLabel}
+ {item.subtype && }
+ {item.source && (
+
+ {t(`admin.users.detail.activity.sources.${item.source}`, {
+ defaultValue: item.source,
+ })}
+
+ )}
+
+
+
+ {item.title && (
+
+ {item.title.length > 160 ? `${item.title.slice(0, 160)}…` : item.title}
+
+ )}
+
+ {formatRelativeTime(item.timestamp, t)}
+
+
+
+ );
+ })}
+
+ {/* Load more */}
+ {items.length < total && (
+
+ )}
+
+ )}
+
+ );
+}
diff --git a/src/locales/en.json b/src/locales/en.json
index e0541f3..3ebb3e2 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -3378,7 +3378,8 @@
"sync": "Synchronization",
"tickets": "Tickets",
"gifts": "Gifts",
- "referrals": "Referrals"
+ "referrals": "Referrals",
+ "activity": "Activity"
},
"noTickets": "No tickets from this user",
"ticketsCount": "tickets",
@@ -3579,6 +3580,66 @@
"searchPlaceholder": "Search by name, email, or Telegram ID...",
"alreadyReferred": "already has referrer",
"noUsersFound": "No users found"
+ },
+ "activity": {
+ "total": "Total events",
+ "empty": "No activity yet",
+ "filters": {
+ "all": "All",
+ "payments": "Payments",
+ "events": "Events",
+ "promo": "Promo",
+ "tickets": "Tickets",
+ "gifts": "Gifts",
+ "referrals": "Referrals",
+ "logins": "Logins"
+ },
+ "types": {
+ "transaction": "Transaction",
+ "event": "Event",
+ "promocode": "Promo code",
+ "coupon": "Coupon",
+ "ticket": "Ticket",
+ "wheel_spin": "Fortune wheel",
+ "poll": "Poll completed",
+ "gift_sent": "Gift sent",
+ "gift_received": "Gift received",
+ "referral_earning": "Referral earning",
+ "cabinet_login": "Cabinet login",
+ "withdrawal": "Withdrawal request"
+ },
+ "sources": {
+ "bot": "Bot",
+ "cabinet": "Cabinet"
+ },
+ "subtypes": {
+ "deposit": "Deposit",
+ "withdrawal": "Charge",
+ "subscription_payment": "Subscription payment",
+ "refund": "Refund",
+ "failed_refund": "Failed refund",
+ "referral_reward": "Referral reward",
+ "poll_reward": "Poll reward",
+ "gift_payment": "Gift payment",
+ "activation": "Activation",
+ "purchase": "Purchase",
+ "subscription_purchase": "Subscription purchase",
+ "renewal": "Renewal",
+ "balance_topup": "Balance top-up",
+ "promo_group_change": "Promo group change",
+ "campaign_registration": "Campaign registration",
+ "referral_link_visit": "Referral link visit",
+ "referral_registration": "Referral registration",
+ "trial_activation": "Trial activation",
+ "open": "Open",
+ "answered": "Answered",
+ "pending": "Pending",
+ "closed": "Closed",
+ "redeemed": "Redeemed",
+ "approved": "Approved",
+ "rejected": "Rejected",
+ "completed": "Completed"
+ }
}
},
"notFound": "User not found",
diff --git a/src/locales/fa.json b/src/locales/fa.json
index 64b6dee..a41c9ed 100644
--- a/src/locales/fa.json
+++ b/src/locales/fa.json
@@ -2882,7 +2882,8 @@
"sync": "همگامسازی",
"tickets": "تیکتها",
"gifts": "هدایا",
- "referrals": "معرفیها"
+ "referrals": "معرفیها",
+ "activity": "فعالیت"
},
"noTickets": "این کاربر تیکتی ندارد",
"ticketsCount": "تیکت",
@@ -3083,7 +3084,67 @@
"areYouSure": "آیا مطمئنید میخواهید ادامه دهید؟",
"title": "عملیات"
},
- "noVpnData": "دادهای از VPN وجود ندارد"
+ "noVpnData": "دادهای از VPN وجود ندارد",
+ "activity": {
+ "total": "مجموع رویدادها",
+ "empty": "هنوز فعالیتی وجود ندارد",
+ "filters": {
+ "all": "همه",
+ "payments": "پرداختها",
+ "events": "رویدادها",
+ "promo": "تخفیفها",
+ "tickets": "تیکتها",
+ "gifts": "هدایا",
+ "referrals": "دعوتها",
+ "logins": "ورودها"
+ },
+ "types": {
+ "transaction": "تراکنش",
+ "event": "رویداد",
+ "promocode": "کد تخفیف",
+ "coupon": "کوپن",
+ "ticket": "تیکت",
+ "wheel_spin": "گردونه شانس",
+ "poll": "نظرسنجی تکمیل شد",
+ "gift_sent": "هدیه ارسال شد",
+ "gift_received": "هدیه دریافت شد",
+ "referral_earning": "درآمد دعوت",
+ "cabinet_login": "ورود به پنل",
+ "withdrawal": "درخواست برداشت"
+ },
+ "sources": {
+ "bot": "ربات",
+ "cabinet": "پنل"
+ },
+ "subtypes": {
+ "deposit": "واریز",
+ "withdrawal": "برداشت",
+ "subscription_payment": "پرداخت اشتراک",
+ "refund": "بازپرداخت",
+ "failed_refund": "بازپرداخت ناموفق",
+ "referral_reward": "پاداش دعوت",
+ "poll_reward": "پاداش نظرسنجی",
+ "gift_payment": "پرداخت هدیه",
+ "activation": "فعالسازی",
+ "purchase": "خرید",
+ "subscription_purchase": "خرید اشتراک",
+ "renewal": "تمدید",
+ "balance_topup": "شارژ موجودی",
+ "promo_group_change": "تغییر گروه تخفیف",
+ "campaign_registration": "ثبتنام کمپین",
+ "referral_link_visit": "بازدید لینک دعوت",
+ "referral_registration": "ثبتنام دعوتی",
+ "trial_activation": "فعالسازی دوره آزمایشی",
+ "open": "باز",
+ "answered": "پاسخ داده شده",
+ "pending": "در انتظار",
+ "closed": "بسته",
+ "redeemed": "استفاده شده",
+ "approved": "تأیید شده",
+ "rejected": "رد شده",
+ "completed": "انجام شده"
+ }
+ }
},
"notFound": "کاربر یافت نشد",
"purchaseCount": "تعداد خرید: {{count}}",
diff --git a/src/locales/ru.json b/src/locales/ru.json
index 3415f79..4b054b5 100644
--- a/src/locales/ru.json
+++ b/src/locales/ru.json
@@ -3785,7 +3785,8 @@
"sync": "Синхронизация",
"tickets": "Тикеты",
"gifts": "Подарки",
- "referrals": "Рефералы"
+ "referrals": "Рефералы",
+ "activity": "Активность"
},
"noTickets": "У пользователя нет тикетов",
"ticketsCount": "тикетов",
@@ -3985,6 +3986,66 @@
"searchPlaceholder": "Поиск по имени, email или Telegram ID...",
"alreadyReferred": "уже чей-то реферал",
"noUsersFound": "Пользователи не найдены"
+ },
+ "activity": {
+ "total": "Всего событий",
+ "empty": "Активности пока нет",
+ "filters": {
+ "all": "Все",
+ "payments": "Платежи",
+ "events": "События",
+ "promo": "Промо",
+ "tickets": "Тикеты",
+ "gifts": "Подарки",
+ "referrals": "Рефералы",
+ "logins": "Входы"
+ },
+ "types": {
+ "transaction": "Транзакция",
+ "event": "Событие",
+ "promocode": "Промокод",
+ "coupon": "Купон",
+ "ticket": "Тикет",
+ "wheel_spin": "Колесо фортуны",
+ "poll": "Опрос пройден",
+ "gift_sent": "Подарок отправлен",
+ "gift_received": "Подарок получен",
+ "referral_earning": "Реферальное начисление",
+ "cabinet_login": "Вход в кабинет",
+ "withdrawal": "Заявка на вывод"
+ },
+ "sources": {
+ "bot": "Бот",
+ "cabinet": "Кабинет"
+ },
+ "subtypes": {
+ "deposit": "Пополнение",
+ "withdrawal": "Списание",
+ "subscription_payment": "Оплата подписки",
+ "refund": "Возврат",
+ "failed_refund": "Неудачный возврат",
+ "referral_reward": "Реферальная награда",
+ "poll_reward": "Награда за опрос",
+ "gift_payment": "Оплата подарка",
+ "activation": "Активация",
+ "purchase": "Покупка",
+ "subscription_purchase": "Покупка подписки",
+ "renewal": "Продление",
+ "balance_topup": "Пополнение баланса",
+ "promo_group_change": "Смена промогруппы",
+ "campaign_registration": "Регистрация по кампании",
+ "referral_link_visit": "Переход по реф. ссылке",
+ "referral_registration": "Реф. регистрация",
+ "trial_activation": "Активация триала",
+ "open": "Открыт",
+ "answered": "Отвечен",
+ "pending": "Ожидает",
+ "closed": "Закрыт",
+ "redeemed": "Погашен",
+ "approved": "Одобрена",
+ "rejected": "Отклонена",
+ "completed": "Выполнена"
+ }
}
},
"notFound": "Пользователь не найден",
diff --git a/src/locales/zh.json b/src/locales/zh.json
index 08eb37c..21b34a7 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -2881,7 +2881,8 @@
"sync": "同步",
"tickets": "工单",
"gifts": "礼物",
- "referrals": "推荐"
+ "referrals": "推荐",
+ "activity": "活动记录"
},
"noTickets": "该用户没有工单",
"ticketsCount": "个工单",
@@ -3082,7 +3083,67 @@
"areYouSure": "确定要继续?",
"title": "操作"
},
- "noVpnData": "无 VPN 数据"
+ "noVpnData": "无 VPN 数据",
+ "activity": {
+ "total": "事件总数",
+ "empty": "暂无活动记录",
+ "filters": {
+ "all": "全部",
+ "payments": "支付",
+ "events": "事件",
+ "promo": "促销",
+ "tickets": "工单",
+ "gifts": "礼物",
+ "referrals": "推荐",
+ "logins": "登录"
+ },
+ "types": {
+ "transaction": "交易",
+ "event": "事件",
+ "promocode": "促销码",
+ "coupon": "优惠券",
+ "ticket": "工单",
+ "wheel_spin": "幸运转盘",
+ "poll": "问卷已完成",
+ "gift_sent": "已发送礼物",
+ "gift_received": "已收到礼物",
+ "referral_earning": "推荐收益",
+ "cabinet_login": "登录后台",
+ "withdrawal": "提现申请"
+ },
+ "sources": {
+ "bot": "机器人",
+ "cabinet": "后台"
+ },
+ "subtypes": {
+ "deposit": "充值",
+ "withdrawal": "扣款",
+ "subscription_payment": "订阅付款",
+ "refund": "退款",
+ "failed_refund": "退款失败",
+ "referral_reward": "推荐奖励",
+ "poll_reward": "问卷奖励",
+ "gift_payment": "礼物付款",
+ "activation": "激活",
+ "purchase": "购买",
+ "subscription_purchase": "订阅购买",
+ "renewal": "续订",
+ "balance_topup": "余额充值",
+ "promo_group_change": "促销组变更",
+ "campaign_registration": "活动注册",
+ "referral_link_visit": "推荐链接访问",
+ "referral_registration": "推荐注册",
+ "trial_activation": "试用激活",
+ "open": "打开",
+ "answered": "已回复",
+ "pending": "等待中",
+ "closed": "已关闭",
+ "redeemed": "已兑换",
+ "approved": "已批准",
+ "rejected": "已拒绝",
+ "completed": "已完成"
+ }
+ }
},
"notFound": "未找到用户",
"purchaseCount": "购买次数:{{count}}",
diff --git a/src/pages/AdminUserDetail.tsx b/src/pages/AdminUserDetail.tsx
index 828a50e..ba63740 100644
--- a/src/pages/AdminUserDetail.tsx
+++ b/src/pages/AdminUserDetail.tsx
@@ -24,6 +24,7 @@ import { GiftsTab } from '../components/admin/userDetail/GiftsTab';
import { SyncTab } from '../components/admin/userDetail/SyncTab';
import { ReferralsTab } from '../components/admin/userDetail/ReferralsTab';
import { BalanceTab } from '../components/admin/userDetail/BalanceTab';
+import { ActivityTab } from '../components/admin/userDetail/ActivityTab';
import { TicketsTab } from '../components/admin/userDetail/TicketsTab';
import { InfoTab } from '../components/admin/userDetail/InfoTab';
import { SubscriptionTab } from '../components/admin/userDetail/SubscriptionTab';
@@ -49,7 +50,7 @@ export default function AdminUserDetail() {
const [user, setUser] = useState