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