diff --git a/.gitignore b/.gitignore index 4133bab..8072b10 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ npm-debug.log* # Misc .DS_Store *.pem +.mcp.json diff --git a/apps/admin/dist.zip b/apps/admin/dist.zip index aebbe55..76a513e 100644 Binary files a/apps/admin/dist.zip and b/apps/admin/dist.zip differ diff --git a/apps/admin/src/sections/user/user-profile/notify-settings-form.tsx b/apps/admin/src/sections/user/user-profile/notify-settings-form.tsx index e72d271..fd74177 100644 --- a/apps/admin/src/sections/user/user-profile/notify-settings-form.tsx +++ b/apps/admin/src/sections/user/user-profile/notify-settings-form.tsx @@ -24,7 +24,7 @@ const notifySettingsSchema = z.object({ enable_balance_notify: z.boolean(), enable_login_notify: z.boolean(), enable_subscribe_notify: z.boolean(), - enable_trade_notify: z.boolean(), + // enable_trade_notify: z.boolean(), }); type NotifySettingsValues = z.infer; @@ -44,7 +44,7 @@ export function NotifySettingsForm({ enable_balance_notify: user.enable_balance_notify, enable_login_notify: user.enable_login_notify, enable_subscribe_notify: user.enable_subscribe_notify, - enable_trade_notify: user.enable_trade_notify, + // enable_trade_notify: user.enable_trade_notify, }, }); @@ -126,7 +126,7 @@ export function NotifySettingsForm({ )} /> - ( @@ -142,7 +142,7 @@ export function NotifySettingsForm({ )} - /> + /> */} diff --git a/apps/admin/src/sections/user/user-subscription/index.tsx b/apps/admin/src/sections/user/user-subscription/index.tsx index 3723f6a..64cfd6c 100644 --- a/apps/admin/src/sections/user/user-subscription/index.tsx +++ b/apps/admin/src/sections/user/user-subscription/index.tsx @@ -451,7 +451,7 @@ function RowReadOnlyActions({ "This action cannot be undone." )} onConfirm={async () => { - await deleteUserSubscribe({ user_subscribe_id: String(row.id) }); + await deleteUserSubscribe({ user_subscribe_id: row.id }); toast.success(t("deleteSuccess", "Deleted successfully")); refresh?.(); }} @@ -636,7 +636,7 @@ function RowMoreActions({ "This action cannot be undone." )} onConfirm={async () => { - await deleteUserSubscribe({ user_subscribe_id: String(row.id) }); + await deleteUserSubscribe({ user_subscribe_id: row.id }); toast.success(t("deleteSuccess", "Deleted successfully")); refresh(); }} diff --git a/apps/admin/src/sections/user/user-subscription/subscription-detail.tsx b/apps/admin/src/sections/user/user-subscription/subscription-detail.tsx index d02ae3d..018e909 100644 --- a/apps/admin/src/sections/user/user-subscription/subscription-detail.tsx +++ b/apps/admin/src/sections/user/user-subscription/subscription-detail.tsx @@ -11,16 +11,86 @@ import { Switch } from "@workspace/ui/components/switch"; import { ConfirmButton } from "@workspace/ui/composed/confirm-button"; import { ProTable } from "@workspace/ui/composed/pro-table/pro-table"; import { + getUserSubscribeById, getUserSubscribeDevices, kickOfflineByUserDevice, } from "@workspace/ui/services/admin/user"; import { deviceIdToHash } from "@workspace/ui/utils/device"; -import { type ReactNode, useState } from "react"; +import { AlertTriangle, Gauge } from "lucide-react"; +import { type ReactNode, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; import { IpLink } from "@/components/ip-link"; import { formatDate } from "@/utils/common"; +function SpeedLimitCard({ subscriptionId }: { subscriptionId: number }) { + const { t } = useTranslation("user"); + const [detail, setDetail] = useState(null); + + useEffect(() => { + getUserSubscribeById({ id: subscriptionId }).then(({ data }) => { + if (data.data) setDetail(data.data); + }); + }, [subscriptionId]); + + if (!detail || detail.status !== 1) return null; + + const baseSpeed = detail.subscribe?.speed_limit ?? 0; + const effectiveSpeed = detail.effective_speed ?? 0; + const isThrottled = detail.is_throttled; + + if (baseSpeed === 0 && !isThrottled) return null; + + return ( +
+ {isThrottled ? ( + + ) : ( + + )} +
+
+ {isThrottled ? ( + <> + {t("throttled", "Speed Throttled")} + + {effectiveSpeed} Mbps + + {baseSpeed > 0 && ( + + {baseSpeed} Mbps + + )} + + ) : ( + <> + + {t("speedLimit", "Speed Limit")} + + + {effectiveSpeed > 0 + ? `${effectiveSpeed} Mbps` + : t("unlimited", "Unlimited")} + + + )} +
+ {isThrottled && detail.throttle_rule && ( +

+ {detail.throttle_rule} +

+ )} +
+
+ ); +} + export function SubscriptionDetail({ trigger, userId, @@ -44,6 +114,7 @@ export function SubscriptionDetail({ {t("onlineDevices", "Online Devices")}
+ {open && } > actions={{ render: (row) => { diff --git a/apps/user/src/sections/user/profile/notify-settings.tsx b/apps/user/src/sections/user/profile/notify-settings.tsx index 7075bc5..8c711a2 100644 --- a/apps/user/src/sections/user/profile/notify-settings.tsx +++ b/apps/user/src/sections/user/profile/notify-settings.tsx @@ -27,7 +27,7 @@ const FormSchema = z.object({ enable_balance_notify: z.boolean(), enable_login_notify: z.boolean(), enable_subscribe_notify: z.boolean(), - enable_trade_notify: z.boolean(), + // enable_trade_notify: z.boolean(), }); export default function NotifySettings() { @@ -39,7 +39,7 @@ export default function NotifySettings() { enable_balance_notify: user?.enable_balance_notify ?? false, enable_login_notify: user?.enable_login_notify ?? false, enable_subscribe_notify: user?.enable_subscribe_notify ?? false, - enable_trade_notify: user?.enable_trade_notify ?? false, + // enable_trade_notify: user?.enable_trade_notify ?? false, }, }); @@ -80,10 +80,10 @@ export default function NotifySettings() { name: "enable_subscribe_notify", label: t("notify.subscribe", "Subscribe"), }, - { - name: "enable_trade_notify", - label: t("notify.finance", "Finance"), - }, + // { + // name: "enable_trade_notify", + // label: t("notify.finance", "Finance"), + // }, ].map(({ name, label }) => (