✨ feat: improve redemption feature i18n and error code handling
- Complete internationalization for redemption records dialog - Add i18n for table headers and unit time translations - Optimize redemption form validation error messages with i18n - Add 50003 error code handling for coupon plan incompatibility - Fix TypeScript errors in redemption-related components - Fix TypeScript errors in user announcement page
This commit is contained in:
parent
93926d9c99
commit
585874777f
@ -26,14 +26,19 @@
|
||||
"halfYear": "Half Year",
|
||||
"month": "Month",
|
||||
"quarter": "Quarter",
|
||||
"quantityRequired": "Quantity is required",
|
||||
"selectPlan": "Select Redemption Plan",
|
||||
"selectUnitTime": "Select Redemption Duration Unit",
|
||||
"subscribePlan": "Redemption Plan",
|
||||
"subscribePlanRequired": "Subscribe plan is required",
|
||||
"totalCount": "Available Uses",
|
||||
"totalCountPlaceholder": "Available Uses",
|
||||
"totalCountRequired": "Total count is required",
|
||||
"unitTime": "Redemption Duration Unit",
|
||||
"unitTimeRequired": "Unit time is required",
|
||||
"year": "Year"
|
||||
},
|
||||
"id": "ID",
|
||||
"loading": "Loading...",
|
||||
"next": "Next",
|
||||
"noRecords": "No records found",
|
||||
|
||||
@ -26,14 +26,19 @@
|
||||
"halfYear": "半年",
|
||||
"month": "月",
|
||||
"quarter": "季度",
|
||||
"quantityRequired": "数量为必填项",
|
||||
"selectPlan": "选择兑换套餐",
|
||||
"selectUnitTime": "选择兑换时长单位",
|
||||
"subscribePlan": "兑换套餐",
|
||||
"subscribePlanRequired": "兑换套餐为必填项",
|
||||
"totalCount": "兑换码可用次数",
|
||||
"totalCountPlaceholder": "兑换码可用次数",
|
||||
"totalCountRequired": "兑换码可用次数为必填项",
|
||||
"unitTime": "兑换时长单位",
|
||||
"unitTimeRequired": "兑换时长单位为必填项",
|
||||
"year": "年"
|
||||
},
|
||||
"id": "ID",
|
||||
"loading": "加载中...",
|
||||
"next": "下一页",
|
||||
"noRecords": "暂无兑换记录",
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { Badge } from "@workspace/ui/components/badge";
|
||||
import { Button } from "@workspace/ui/components/button";
|
||||
import { Switch } from "@workspace/ui/components/switch";
|
||||
import { ConfirmButton } from "@workspace/ui/composed/confirm-button";
|
||||
|
||||
@ -26,14 +26,14 @@ import { useTranslation } from "react-i18next";
|
||||
import { z } from "zod";
|
||||
import { useSubscribe } from "@/stores/subscribe";
|
||||
|
||||
const formSchema = z.object({
|
||||
const getFormSchema = (t: (key: string, defaultValue: string) => string) => z.object({
|
||||
id: z.number().optional(),
|
||||
code: z.string().optional(),
|
||||
batch_count: z.number().optional(),
|
||||
total_count: z.number().min(1, "Total count is required"),
|
||||
subscribe_plan: z.number().min(1, "Subscribe plan is required"),
|
||||
unit_time: z.string().min(1, "Unit time is required"),
|
||||
quantity: z.number().min(1, "Quantity is required"),
|
||||
total_count: z.number().min(1, t("form.totalCountRequired", "Total count is required")),
|
||||
subscribe_plan: z.number().min(1, t("form.subscribePlanRequired", "Subscribe plan is required")),
|
||||
unit_time: z.string().min(1, t("form.unitTimeRequired", "Unit time is required")),
|
||||
quantity: z.number().min(1, t("form.quantityRequired", "Quantity is required")),
|
||||
});
|
||||
|
||||
interface RedemptionFormProps<T> {
|
||||
@ -52,6 +52,7 @@ export default function RedemptionForm<T extends Record<string, any>>({
|
||||
title,
|
||||
}: RedemptionFormProps<T>) {
|
||||
const { t } = useTranslation("redemption");
|
||||
const formSchema = getFormSchema(t);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const form = useForm({
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { Badge } from "@workspace/ui/components/badge";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@ -81,7 +80,7 @@ export default function RedemptionRecords({
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>ID</TableHead>
|
||||
<TableHead>{t("id", "ID")}</TableHead>
|
||||
<TableHead>{t("userId", "User ID")}</TableHead>
|
||||
<TableHead>{t("subscribeId", "Subscribe ID")}</TableHead>
|
||||
<TableHead>{t("unitTime", "Unit Time")}</TableHead>
|
||||
@ -90,20 +89,29 @@ export default function RedemptionRecords({
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{records.map((record) => (
|
||||
<TableRow key={record.id}>
|
||||
<TableCell>{record.id}</TableCell>
|
||||
<TableCell>{record.user_id}</TableCell>
|
||||
<TableCell>{record.subscribe_id}</TableCell>
|
||||
<TableCell>{record.unit_time}</TableCell>
|
||||
<TableCell>{record.quantity}</TableCell>
|
||||
<TableCell>
|
||||
{record.redeemed_at
|
||||
? formatDate(record.redeemed_at)
|
||||
: "--"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
{records.map((record) => {
|
||||
const unitTimeMap: Record<string, string> = {
|
||||
day: t("form.day", "Day"),
|
||||
month: t("form.month", "Month"),
|
||||
quarter: t("form.quarter", "Quarter"),
|
||||
half_year: t("form.halfYear", "Half Year"),
|
||||
year: t("form.year", "Year"),
|
||||
};
|
||||
return (
|
||||
<TableRow key={record.id}>
|
||||
<TableCell>{record.id}</TableCell>
|
||||
<TableCell>{record.user_id}</TableCell>
|
||||
<TableCell>{record.subscribe_id}</TableCell>
|
||||
<TableCell>{unitTimeMap[record.unit_time] || record.unit_time}</TableCell>
|
||||
<TableCell>{record.quantity}</TableCell>
|
||||
<TableCell>
|
||||
{record.redeemed_at
|
||||
? formatDate(record.redeemed_at)
|
||||
: "--"}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{total > pagination.size && (
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
"40005": "You do not have access permission, please contact the administrator if you have any questions.",
|
||||
"50001": "Corresponding coupon information not found, please check and try again.",
|
||||
"50002": "The coupon has been used, cannot be used again.",
|
||||
"50003": "This coupon code is not supported by the current purchase plan.",
|
||||
"60001": "Subscription has expired, please renew before using.",
|
||||
"60002": "Unable to use the subscription at the moment, please try again later.",
|
||||
"60003": "An existing subscription is detected. Please cancel it before proceeding.",
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
"40005": "您没有访问权限,如有疑问请联系管理员。",
|
||||
"50001": "找不到对应的优惠券信息,请检查后重试。",
|
||||
"50002": "该优惠券已被使用,无法再次使用。",
|
||||
"50003": "该优惠码不被当前购买套餐支持。",
|
||||
"60001": "订阅已过期,请续费后使用。",
|
||||
"60002": "暂时无法使用该订阅,请稍后再试。",
|
||||
"60003": "检测到现有订阅,请先取消后再继续。",
|
||||
|
||||
@ -119,6 +119,10 @@ function handleError(response: {
|
||||
"components:error.50002",
|
||||
"The coupon has been used, cannot be used again."
|
||||
),
|
||||
50003: t(
|
||||
"components:error.50003",
|
||||
"This coupon code is not supported by the current purchase plan."
|
||||
),
|
||||
60001: t(
|
||||
"components:error.60001",
|
||||
"Subscription has expired, please renew before using."
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user