diff --git a/apps/user/public/assets/locales/en-US/dashboard.json b/apps/user/public/assets/locales/en-US/dashboard.json index 8ca073d..bbc8be3 100644 --- a/apps/user/public/assets/locales/en-US/dashboard.json +++ b/apps/user/public/assets/locales/en-US/dashboard.json @@ -31,5 +31,13 @@ "subscriptionUrl": "Subscription URL", "totalTraffic": "Total Traffic", "unknown": "Unknown", - "used": "Used" + "used": "Used", + "redeemCode": "Redeem Code", + "redeemCodeTitle": "Redeem Code", + "redeemCodeDescription": "Enter redemption code to get subscription plan", + "enterRedemptionCode": "Please enter redemption code", + "redeemButton": "Redeem Now", + "redeeming": "Redeeming...", + "redeemSuccess": "Redemption successful! Subscription has been activated.", + "redeemFailed": "Redemption failed" } diff --git a/apps/user/public/assets/locales/zh-CN/dashboard.json b/apps/user/public/assets/locales/zh-CN/dashboard.json index 5e573b2..2eb4e5a 100644 --- a/apps/user/public/assets/locales/zh-CN/dashboard.json +++ b/apps/user/public/assets/locales/zh-CN/dashboard.json @@ -31,5 +31,13 @@ "subscriptionUrl": "订阅链接", "totalTraffic": "总流量", "unknown": "未知", - "used": "已使用" + "used": "已使用", + "redeemCode": "兑换 CDK", + "redeemCodeTitle": "CDK 兑换", + "redeemCodeDescription": "输入兑换码以获取订阅套餐", + "enterRedemptionCode": "请输入兑换码", + "redeemButton": "立即兑换", + "redeeming": "兑换中...", + "redeemSuccess": "兑换成功!", + "redeemFailed": "兑换失败" } diff --git a/apps/user/src/sections/user/dashboard/content.tsx b/apps/user/src/sections/user/dashboard/content.tsx index db0b531..09ef784 100644 --- a/apps/user/src/sections/user/dashboard/content.tsx +++ b/apps/user/src/sections/user/dashboard/content.tsx @@ -47,6 +47,7 @@ import Subscribe from "../../subscribe"; import Renewal from "../../subscribe/renewal"; import ResetTraffic from "../../subscribe/reset-traffic"; import Unsubscribe from "../../subscribe/unsubscribe"; +import RedeemCode from "./redeem-code"; const platforms: (keyof API.DownloadLink)[] = [ "windows", @@ -164,6 +165,7 @@ export default function Content() { +
{availablePlatforms.length > 0 && ( void; +} + +export default function RedeemCode({ onSuccess }: RedeemCodeProps) { + const { t } = useTranslation("dashboard"); + const [code, setCode] = useState(""); + + const redeemMutation = useMutation({ + mutationFn: (code: string) => redeemCode({ code }), + onSuccess: (response) => { + toast.success(response.data.message || t("redeemSuccess", "兑换成功")); + setCode(""); + onSuccess?.(); + }, + onError: (error: any) => { + const errorMessage = + error?.response?.data?.message || t("redeemFailed", "兑换失败"); + toast.error(errorMessage); + }, + }); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (!code.trim()) { + toast.error(t("pleaseEnterCode", "请输入兑换码")); + return; + } + redeemMutation.mutate(code.trim()); + }; + + return ( + + + {t("redeemCode", "CDK 兑换")} + + {t("redeemCodeDescription", "输入兑换码即可兑换对应的订阅套餐")} + + + +
+
+ +
+ setCode(e.target.value)} + placeholder={t( + "enterRedemptionCode", + "请输入兑换码" + )} + value={code} + /> + +
+
+
+
+
+ ); +} diff --git a/packages/ui/src/services/user/user.ts b/packages/ui/src/services/user/user.ts index d7a25ca..f931d99 100644 --- a/packages/ui/src/services/user/user.ts +++ b/packages/ui/src/services/user/user.ts @@ -268,6 +268,24 @@ export async function updateUserRules( ); } +/** Redeem Code POST /v1/public/redemption/ */ +export async function redeemCode( + body: { code: string }, + options?: { [key: string]: any } +) { + return request( + `${import.meta.env.VITE_API_PREFIX || ""}/v1/public/redemption/`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + data: body, + ...(options || {}), + } + ); +} + /** Query User Subscribe GET /v1/public/user/subscribe */ export async function queryUserSubscribe(options?: { [key: string]: any }) { return request(