mirror of
https://github.com/jarvis2f/vortex.git
synced 2024-11-16 03:32:41 +08:00
refactor: update translations for balance components in user-[userId] context
This commit is contained in:
parent
7b90c9021b
commit
5804d346e7
|
@ -650,7 +650,10 @@
|
|||
},
|
||||
"user-[userId]-balance": {
|
||||
"available_balance": "Available Balance",
|
||||
"earnings_amount": "Earnings Amount"
|
||||
"balance": "Balance",
|
||||
"earnings": "Earnings",
|
||||
"earnings_amount": "Earnings Amount",
|
||||
"check_your_account_balance": "Check your account balance"
|
||||
},
|
||||
"user-[userId]-balance-log": {
|
||||
"balance": "Balance",
|
||||
|
@ -681,17 +684,17 @@
|
|||
"recharge_code": "Recharge Code"
|
||||
},
|
||||
"user-[userId]-recharge-depay": {
|
||||
"after_clicking_confirm": "After clicking confirm",
|
||||
"and": "and",
|
||||
"confirm": "Confirm",
|
||||
"enter_crypto_wallet_select_payment_method": "you will enter the crypto wallet to select a payment method",
|
||||
"invalid_amount": "Invalid amount",
|
||||
"minimum_recharge_amount": "Minimum recharge amount",
|
||||
"notes": "Notes",
|
||||
"note_1": "Supports <important>USDC</important> and <important>USDT</important> recharge, with a minimum recharge amount of ${rechargeMinAmount}",
|
||||
"note_2": "After clicking Confirm, you will enter the encrypted wallet to select the payment method.",
|
||||
"note_3": "Top-ups are subject to a 1.5% fee.",
|
||||
"recharge": "Recharge",
|
||||
"recharge_amount": "Recharge Amount",
|
||||
"recharge_failed": "Recharge Failed",
|
||||
"recharge_handling_fee": "Recharge requires a handling fee of",
|
||||
"recharge_successful": "Recharge Successful",
|
||||
"support": "Support",
|
||||
"supported_networks": "Supported networks"
|
||||
|
@ -712,8 +715,7 @@
|
|||
"please_provide": "Please provide",
|
||||
"receiving_address": "Receiving Address",
|
||||
"request_withdrawal": "Request Withdrawal",
|
||||
"request_withdrawal_to_specified_address": "Request withdrawal to the specified address",
|
||||
"subject_to_actual_received_amount": "Subject to the actual received amount",
|
||||
"request_withdrawal_desc": "When applying for withdrawal to the designated address, part of the handling fee needs to be deducted, and the actual amount received shall prevail.",
|
||||
"withdrawal": "Withdrawal"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -650,7 +650,10 @@
|
|||
},
|
||||
"user-[userId]-balance": {
|
||||
"available_balance": "可消费余额",
|
||||
"earnings_amount": "收益金额"
|
||||
"balance": "余额",
|
||||
"earnings": "收益",
|
||||
"earnings_amount": "收益金额",
|
||||
"check_your_account_balance": "查看你的账户余额"
|
||||
},
|
||||
"user-[userId]-balance-log": {
|
||||
"balance": "余额",
|
||||
|
@ -681,17 +684,17 @@
|
|||
"recharge_code": "充值码"
|
||||
},
|
||||
"user-[userId]-recharge-depay": {
|
||||
"after_clicking_confirm": "点击确认后",
|
||||
"and": "和",
|
||||
"confirm": "确认",
|
||||
"enter_crypto_wallet_select_payment_method": "将会进入加密钱包选择支付方式",
|
||||
"invalid_amount": "无效的金额",
|
||||
"minimum_recharge_amount": "充值金额最低",
|
||||
"notes": "注意事项",
|
||||
"note_1": "支持 <b>USDC</b> 和 <b>USDT</b> 充值,充值金额最低 ${rechargeMinAmount}",
|
||||
"note_2": "点击确认后,将会进入加密钱包选择支付方式。",
|
||||
"note_3": "充值需要收取 1.5% 的手续费。",
|
||||
"recharge": "充值",
|
||||
"recharge_amount": "充值金额",
|
||||
"recharge_failed": "充值失败",
|
||||
"recharge_handling_fee": "充值需要收取",
|
||||
"recharge_successful": "充值成功",
|
||||
"support": "支持",
|
||||
"supported_networks": "支持的网络"
|
||||
|
@ -707,13 +710,11 @@
|
|||
"user-[userId]-withdrawal-balance": {
|
||||
"amount": "金额",
|
||||
"current_earnings_balance": "当前收益余额",
|
||||
"deduct_handling_fee": "需要扣除部分手续费",
|
||||
"minimum_withdrawal_amount": "最低提现金额为",
|
||||
"please_provide": "请提供",
|
||||
"receiving_address": "收款地址",
|
||||
"request_withdrawal": "申请提现",
|
||||
"request_withdrawal_to_specified_address": "申请提现到指定的地址",
|
||||
"subject_to_actual_received_amount": "以实际到账金额为准",
|
||||
"request_withdrawal_desc": "申请提现到指定的地址,需要扣除部分手续费,以实际到账金额为准",
|
||||
"withdrawal": "提现"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "~/lib/ui/tooltip";
|
|||
import type { RouterOutputs } from "~/trpc/shared";
|
||||
import { MoneyInput } from "~/lib/ui/money-input";
|
||||
import { type BalanceType } from "@prisma/client";
|
||||
import { useTranslations } from "use-intl";
|
||||
|
||||
export default function BalanceLog({
|
||||
userId,
|
||||
|
@ -17,6 +18,7 @@ export default function BalanceLog({
|
|||
userId: string;
|
||||
balanceType?: BalanceType;
|
||||
}) {
|
||||
const t = useTranslations("user-[userId]-balance-log");
|
||||
const getLogs = api.user.getBalanceLogs.useInfiniteQuery(
|
||||
{
|
||||
id: userId,
|
||||
|
@ -105,15 +107,15 @@ export default function BalanceLog({
|
|||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>余额历史</CardHeader>
|
||||
<CardHeader>{t("balance_history")}</CardHeader>
|
||||
<CardContent>
|
||||
<div className="border-b">
|
||||
<div className="flex space-x-2 py-1 text-left text-sm text-muted-foreground">
|
||||
<div className="w-[170px]">时间</div>
|
||||
<div className="w-[170px]">{t("time")}</div>
|
||||
<div className="grid flex-1 grid-cols-4 gap-2">
|
||||
<p>变动金额</p>
|
||||
<p>余额</p>
|
||||
<p className="col-span-2">其它信息</p>
|
||||
<p>{t("change_amount")}</p>
|
||||
<p>{t("balance")}</p>
|
||||
<p className="col-span-2">{t("other_info")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,6 +7,7 @@ import RechargeBalance from "~/app/[local]/(manage)/user/[userId]/_components/re
|
|||
import { MoneyInput } from "~/lib/ui/money-input";
|
||||
import { BalanceType } from "@prisma/client";
|
||||
import WithdrawalBalance from "~/app/[local]/(manage)/user/[userId]/_components/withdrawal-balance";
|
||||
import { useTranslations } from "use-intl";
|
||||
|
||||
interface BalanceProps {
|
||||
wallet: {
|
||||
|
@ -18,13 +19,13 @@ interface BalanceProps {
|
|||
|
||||
export default function Balance({ wallet, userId }: BalanceProps) {
|
||||
const { data: session } = useSession();
|
||||
|
||||
const t = useTranslations("user-[userId]-balance");
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
{wallet?.balanceType === BalanceType.CONSUMPTION
|
||||
? "可消费余额"
|
||||
: "收益金额"}
|
||||
? t("available_balance")
|
||||
: t("earnings_amount")}
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<MoneyInput displayType="text" value={wallet?.balance} />
|
||||
|
|
|
@ -18,6 +18,7 @@ import { Button } from "~/lib/ui/button";
|
|||
import { useEffect, useState } from "react";
|
||||
import { type RouterOutputs } from "~/trpc/shared";
|
||||
import { useTrack } from "~/lib/hooks/use-track";
|
||||
import { useTranslations } from "use-intl";
|
||||
|
||||
const updateProfileFormSchema = z.object({
|
||||
name: z.string().min(1).max(255).optional(),
|
||||
|
@ -29,6 +30,7 @@ export default function ProfileForm({
|
|||
}: {
|
||||
user: RouterOutputs["user"]["getOne"];
|
||||
}) {
|
||||
const t = useTranslations("user-[userId]-profile-form");
|
||||
const updateProfileMutation = api.user.updateProfile.useMutation();
|
||||
const { track } = useTrack();
|
||||
const form = useForm<z.infer<typeof updateProfileFormSchema>>({
|
||||
|
@ -68,11 +70,13 @@ export default function ProfileForm({
|
|||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>名称</FormLabel>
|
||||
<FormLabel>{t("name")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>显示在您的个人资料中的名称</FormDescription>
|
||||
<FormDescription>
|
||||
{t("name_displayed_in_profile")}
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
|
@ -82,11 +86,11 @@ export default function ProfileForm({
|
|||
name="image"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>头像</FormLabel>
|
||||
<FormLabel>{t("avatar")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>头像链接</FormDescription>
|
||||
<FormDescription>{t("avatar_link")}</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
|
@ -98,7 +102,7 @@ export default function ProfileForm({
|
|||
loading={updateProfileMutation.isLoading}
|
||||
success={updateProfileMutation.isSuccess}
|
||||
>
|
||||
保存
|
||||
{t("save")}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -14,6 +14,7 @@ import { api } from "~/trpc/react";
|
|||
import React, { useState } from "react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { useTrack } from "~/lib/hooks/use-track";
|
||||
import { useTranslations } from "use-intl";
|
||||
|
||||
const RechargeDepay = dynamic(() => import("./recharge-depay"), {
|
||||
ssr: false,
|
||||
|
@ -28,6 +29,7 @@ const RechargeDepay = dynamic(() => import("./recharge-depay"), {
|
|||
});
|
||||
|
||||
export default function RechargeBalance({ userId }: { userId: string }) {
|
||||
const t = useTranslations("user-[userId]-recharge-balance");
|
||||
const [code, setCode] = useState("");
|
||||
const rechargeBalanceByCodeMutation =
|
||||
api.user.rechargeBalanceByCode.useMutation();
|
||||
|
@ -38,27 +40,29 @@ export default function RechargeBalance({ userId }: { userId: string }) {
|
|||
<DialogTrigger asChild>
|
||||
<Button>
|
||||
<GemIcon className="mr-2 h-5 w-5" />
|
||||
充值
|
||||
{t("recharge")}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="h-full w-full md:h-auto md:min-w-20">
|
||||
<DialogHeader>
|
||||
<DialogTitle>余额充值</DialogTitle>
|
||||
<DialogTitle>{t("balance_recharge")}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Tabs defaultValue="recharge">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsTrigger value="recharge">充值</TabsTrigger>
|
||||
<TabsTrigger value="recharge_code">充值码</TabsTrigger>
|
||||
<TabsTrigger value="recharge">{t("recharge")}</TabsTrigger>
|
||||
<TabsTrigger value="recharge_code">
|
||||
{t("recharge_code")}
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value={"recharge"} className="h-[570px]">
|
||||
<TabsContent value={"recharge"} className="h-[600px]">
|
||||
<RechargeDepay />
|
||||
</TabsContent>
|
||||
<TabsContent value="recharge_code">
|
||||
<div className="mb-4">
|
||||
<Label>充值码</Label>
|
||||
<Label>{t("recharge_code")}</Label>
|
||||
<div className="mt-1">
|
||||
<Input
|
||||
placeholder="请输入充值码"
|
||||
placeholder={t("enter_recharge_code")}
|
||||
value={code}
|
||||
onChange={(e) => setCode(e.target.value)}
|
||||
/>
|
||||
|
@ -80,7 +84,7 @@ export default function RechargeBalance({ userId }: { userId: string }) {
|
|||
loading={rechargeBalanceByCodeMutation.isLoading}
|
||||
success={rechargeBalanceByCodeMutation.isSuccess}
|
||||
>
|
||||
充值
|
||||
{t("recharge")}
|
||||
</Button>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
|
|
@ -11,6 +11,7 @@ import { type RouterOutputs } from "~/trpc/shared";
|
|||
import Image from "next/image";
|
||||
import Blockchains from "@depay/web3-blockchains";
|
||||
import { useTrack } from "~/lib/hooks/use-track";
|
||||
import { useTranslations } from "use-intl";
|
||||
|
||||
const dePayWidgetStyles = `
|
||||
.PoweredByWrapper {
|
||||
|
@ -39,6 +40,7 @@ const dePayWidgetStyles = `
|
|||
`;
|
||||
|
||||
export default function RechargeDepay() {
|
||||
const t = useTranslations("user-[userId]-recharge-depay");
|
||||
const dePayRef = useRef(null);
|
||||
const [amount, setAmount] = useState("0");
|
||||
const [dePay, setDePay] = useState<{
|
||||
|
@ -78,15 +80,15 @@ export default function RechargeDepay() {
|
|||
amount: data.amount,
|
||||
});
|
||||
toast({
|
||||
title: "充值成功",
|
||||
description: `充值金额 ${data.amount} USDC/USDT`,
|
||||
title: t("recharge_successful"),
|
||||
description: `${t("recharge_amount")} ${data.amount} USDC/USDT`,
|
||||
});
|
||||
} else if (data?.status === "FAILED") {
|
||||
track("recharge-depay-fail", {
|
||||
amount: data.amount,
|
||||
});
|
||||
toast({
|
||||
title: "充值失败",
|
||||
title: t("recharge_failed"),
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
|
@ -118,7 +120,7 @@ export default function RechargeDepay() {
|
|||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
const configuration: DePayWidgets.PaymentOptions = {
|
||||
title: "充值",
|
||||
title: t("recharge"),
|
||||
container: dePayRef.current,
|
||||
integration: dePayIntegrationId,
|
||||
payload: payload,
|
||||
|
@ -165,8 +167,8 @@ export default function RechargeDepay() {
|
|||
const amountNumber = parseFloat(amount);
|
||||
if (isNaN(amountNumber) || amountNumber < rechargeMinAmount) {
|
||||
toast({
|
||||
title: "无效的金额",
|
||||
description: `充值金额最低 ${rechargeMinAmount} USDC/USDT`,
|
||||
title: t("invalid_amount"),
|
||||
description: `${t("recharge_amount")} ${rechargeMinAmount} USDC/USDT`,
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
|
@ -191,7 +193,7 @@ export default function RechargeDepay() {
|
|||
{!dePay.loaded && (
|
||||
<>
|
||||
<div className="space-y-4">
|
||||
<Label>充值金额</Label>
|
||||
<Label>{t("recharge_amount")}</Label>
|
||||
<MoneyInput
|
||||
value={amount}
|
||||
onValueChange={(values) => {
|
||||
|
@ -201,21 +203,22 @@ export default function RechargeDepay() {
|
|||
<Button onClick={() => createPayment()} className="w-full">
|
||||
<TetherIcon className="mr-2 h-5 w-5" />
|
||||
<USDCIcon className="mr-2 h-5 w-5" />
|
||||
确认
|
||||
{t("confirm")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<h3 className="mt-4 text-lg font-semibold">注意事项</h3>
|
||||
<h3 className="mt-4 text-lg font-semibold">{t("notes")}</h3>
|
||||
<p className="text-sm">
|
||||
1. 支持 <b>USDC</b> 和 <b>USDT</b> 充值,充值金额最低 $
|
||||
{rechargeMinAmount}。
|
||||
1.{" "}
|
||||
{t.rich("note_1", {
|
||||
important: (children) => <b>{children}</b>,
|
||||
rechargeMinAmount: rechargeMinAmount,
|
||||
})}
|
||||
</p>
|
||||
<p className="text-sm">
|
||||
2. 点击确认后,将会进入加密钱包选择支付方式。
|
||||
</p>
|
||||
<p className="text-sm">3. 充值需要收取 1.5% 的手续费。</p>
|
||||
<p className="text-sm">2. {t("note_2")}</p>
|
||||
<p className="text-sm">3. {t("note_3")}</p>
|
||||
<div>
|
||||
<p className="text-md mb-2">支持的网络</p>
|
||||
<p className="text-md mb-2">{t("supported_networks")}</p>
|
||||
<ul className="space-y-2">
|
||||
{[
|
||||
Blockchains.avalanche,
|
||||
|
|
|
@ -29,6 +29,7 @@ import { Label } from "~/lib/ui/label";
|
|||
import { MoneyInput } from "~/lib/ui/money-input";
|
||||
import { type BalanceType } from "@prisma/client";
|
||||
import { useTrack } from "~/lib/hooks/use-track";
|
||||
import { useTranslations } from "use-intl";
|
||||
|
||||
export const updateBalanceFormSchema = z.object({
|
||||
amount: z.preprocess(
|
||||
|
@ -45,6 +46,7 @@ export default function UpdateBalance({
|
|||
userId: string;
|
||||
balanceType?: BalanceType;
|
||||
}) {
|
||||
const t = useTranslations("user-[userId]-update-balance");
|
||||
const [deduct, setDeduct] = useState(false);
|
||||
const { track } = useTrack();
|
||||
const updateBalanceMutation = api.user.updateBalance.useMutation({});
|
||||
|
@ -74,13 +76,13 @@ export default function UpdateBalance({
|
|||
<DialogTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<HandCoinsIcon className="mr-2 h-5 w-5" />
|
||||
更新余额
|
||||
{t("update_balance")}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="min-w-20">
|
||||
<DialogHeader>
|
||||
<DialogTitle>更新余额</DialogTitle>
|
||||
<DialogDescription>为用户添加或减少余额</DialogDescription>
|
||||
<DialogTitle>{t("update_balance")}</DialogTitle>
|
||||
<DialogDescription>{t("add_or_subtract_balance")}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form className="max-h-[30rem] space-y-3 overflow-y-auto p-1">
|
||||
|
@ -89,7 +91,7 @@ export default function UpdateBalance({
|
|||
name="amount"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>金额</FormLabel>
|
||||
<FormLabel>{t("amount")}</FormLabel>
|
||||
<FormControl>
|
||||
<MoneyInput
|
||||
value={field.value}
|
||||
|
@ -107,7 +109,7 @@ export default function UpdateBalance({
|
|||
name="extra"
|
||||
render={({ field }) => (
|
||||
<FormItem className={cn("col-span-4")}>
|
||||
<FormLabel>备注</FormLabel>
|
||||
<FormLabel>{t("remark")}</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea {...field} />
|
||||
</FormControl>
|
||||
|
@ -119,7 +121,7 @@ export default function UpdateBalance({
|
|||
</Form>
|
||||
<DialogFooter>
|
||||
<div className="flex items-center gap-3">
|
||||
<Label htmlFor="deduct">减少余额</Label>
|
||||
<Label htmlFor="deduct">{t("reduce_balance")}</Label>
|
||||
<Switch id="deduct" onCheckedChange={setDeduct} checked={deduct} />
|
||||
</div>
|
||||
<Button
|
||||
|
@ -127,7 +129,7 @@ export default function UpdateBalance({
|
|||
loading={updateBalanceMutation.isLoading}
|
||||
success={updateBalanceMutation.isSuccess}
|
||||
>
|
||||
保存
|
||||
{t("save")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
|
|
@ -26,6 +26,7 @@ import { api } from "~/trpc/react";
|
|||
import { useForm } from "react-hook-form";
|
||||
import { useMemo } from "react";
|
||||
import { useTrack } from "~/lib/hooks/use-track";
|
||||
import { useTranslations } from "use-intl";
|
||||
|
||||
export const withdrawalBalanceFormSchema = z.object({
|
||||
amount: z.preprocess(
|
||||
|
@ -36,6 +37,7 @@ export const withdrawalBalanceFormSchema = z.object({
|
|||
});
|
||||
|
||||
export default function WithdrawalBalance({ balance }: { balance: string }) {
|
||||
const t = useTranslations("user-[userId]-withdrawal-balance");
|
||||
const createWithdrawalMutation = api.withdrawal.create.useMutation({});
|
||||
const { data: config } = api.system.getConfig.useQuery({
|
||||
key: "WITHDRAW_MIN_AMOUNT",
|
||||
|
@ -64,15 +66,17 @@ export default function WithdrawalBalance({ balance }: { balance: string }) {
|
|||
<DialogTrigger asChild>
|
||||
<Button>
|
||||
<CircleDollarSignIcon className="mr-2 h-5 w-5" />
|
||||
申请提现
|
||||
{t("request_withdrawal")}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="min-w-20">
|
||||
<DialogHeader>
|
||||
<DialogTitle>提现</DialogTitle>
|
||||
<DialogTitle>{t("withdrawal")}</DialogTitle>
|
||||
<DialogDescription className="space-y-1">
|
||||
<p>申请提现到指定的地址,需要扣除部分手续费,以实际到账金额为准</p>
|
||||
<p>当前收益余额:${balance}</p>
|
||||
<p>{t("request_withdrawal_desc")}</p>
|
||||
<p>
|
||||
{t("current_earnings_balance")}:${balance}
|
||||
</p>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
|
@ -82,9 +86,9 @@ export default function WithdrawalBalance({ balance }: { balance: string }) {
|
|||
name="amount"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>金额</FormLabel>
|
||||
<FormLabel>{t("amount")}</FormLabel>
|
||||
<FormDescription>
|
||||
最低提现金额为 ${withdrawMinAmount}
|
||||
{t("minimum_withdrawal_amount")} ${withdrawMinAmount}
|
||||
</FormDescription>
|
||||
<FormControl>
|
||||
<MoneyInput
|
||||
|
@ -107,8 +111,10 @@ export default function WithdrawalBalance({ balance }: { balance: string }) {
|
|||
name="address"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>收款地址</FormLabel>
|
||||
<FormDescription>请提供 USDC 收款地址</FormDescription>
|
||||
<FormLabel>{t("receiving_address")}</FormLabel>
|
||||
<FormDescription>
|
||||
{t("please_provide")} USDC {t("receiving_address")}
|
||||
</FormDescription>
|
||||
<FormControl>
|
||||
<Input {...field} autoFocus />
|
||||
</FormControl>
|
||||
|
@ -128,7 +134,7 @@ export default function WithdrawalBalance({ balance }: { balance: string }) {
|
|||
loading={createWithdrawalMutation.isLoading}
|
||||
success={createWithdrawalMutation.isSuccess}
|
||||
>
|
||||
申请提现
|
||||
{t("request_withdrawal")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
|
|
@ -1,32 +1,36 @@
|
|||
import { Separator } from "../../../../../../lib/ui/separator";
|
||||
import { Separator } from "~/lib/ui/separator";
|
||||
import { api } from "~/trpc/server";
|
||||
import { Label } from "~/lib/ui/label";
|
||||
import UpdatePasswordDialog from "~/app/[local]/_components/update-password-dialog";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
|
||||
export default async function UserAccountPage({
|
||||
params: { userId },
|
||||
}: {
|
||||
params: { userId: string };
|
||||
}) {
|
||||
const t = await getTranslations("user-[userId]-account");
|
||||
const user = await api.user.getOne.query({ id: userId });
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-medium">账号</h3>
|
||||
<p className="text-sm text-muted-foreground">查看和更新你的账号信息</p>
|
||||
<h3 className="text-lg font-medium">{t("account")}</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("view_update_account_info")}
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-1">
|
||||
<Label>邮箱</Label>
|
||||
<Label>{t("email")}</Label>
|
||||
<p className="text-muted-foreground">{user.email}</p>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<div className="space-y-1">
|
||||
<Label>密码</Label>
|
||||
<Label>{t("password")}</Label>
|
||||
<p className="text-muted-foreground">
|
||||
{user.isSetupPassword ? "********" : "未设置密码"}
|
||||
{user.isSetupPassword ? "********" : t("password_not_set")}
|
||||
</p>
|
||||
</div>
|
||||
<UpdatePasswordDialog
|
||||
|
|
|
@ -5,27 +5,31 @@ import BalanceLog from "~/app/[local]/(manage)/user/[userId]/_components/balance
|
|||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/lib/ui/tabs";
|
||||
import { getServerAuthSession } from "~/server/auth";
|
||||
import { BalanceType, Role } from "@prisma/client";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
|
||||
export default async function UserBalancePage({
|
||||
params: { userId },
|
||||
}: {
|
||||
params: { userId: string };
|
||||
}) {
|
||||
const t = await getTranslations("user-[userId]-balance");
|
||||
const wallet = await api.user.getWallet.query({ id: userId });
|
||||
const session = await getServerAuthSession();
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-medium">余额</h3>
|
||||
<p className="text-sm text-muted-foreground">查看你的账户余额</p>
|
||||
<h3 className="text-lg font-medium">{t("balance")}</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("check_your_account_balance")}
|
||||
</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<Tabs defaultValue="CONSUMPTION">
|
||||
<TabsList>
|
||||
<TabsTrigger value="CONSUMPTION">余额</TabsTrigger>
|
||||
<TabsTrigger value="CONSUMPTION">{t("balance")}</TabsTrigger>
|
||||
{session?.user.roles.includes(Role.AGENT_PROVIDER) && (
|
||||
<TabsTrigger value="INCOME">收益</TabsTrigger>
|
||||
<TabsTrigger value="INCOME">{t("earnings")}</TabsTrigger>
|
||||
)}
|
||||
</TabsList>
|
||||
<TabsContent value="CONSUMPTION" className="space-y-6">
|
||||
|
|
|
@ -2,30 +2,32 @@ import { Separator } from "~/lib/ui/separator";
|
|||
import { type ReactNode } from "react";
|
||||
import { SidebarNav } from "~/app/[local]/_components/sidebar-nav";
|
||||
import type { Metadata } from "next";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "用户中心 - vortex",
|
||||
description: "用户中心",
|
||||
};
|
||||
|
||||
export default function UserLayout({
|
||||
export default async function UserLayout({
|
||||
children,
|
||||
params: { userId },
|
||||
}: {
|
||||
children: ReactNode;
|
||||
params: { userId: string };
|
||||
}) {
|
||||
const t = await getTranslations("user-[userId]-layout");
|
||||
const sidebarNavItems = [
|
||||
{
|
||||
title: "个人资料",
|
||||
title: t("profile"),
|
||||
href: `/user/${userId}`,
|
||||
},
|
||||
{
|
||||
title: "账户",
|
||||
title: t("account"),
|
||||
href: `/user/${userId}/account`,
|
||||
},
|
||||
{
|
||||
title: "余额",
|
||||
title: t("balance"),
|
||||
href: `/user/${userId}/balance`,
|
||||
},
|
||||
];
|
||||
|
@ -33,9 +35,11 @@ export default function UserLayout({
|
|||
return (
|
||||
<div className="space-y-6 p-4 pb-16">
|
||||
<div className="space-y-0.5">
|
||||
<h2 className="text-2xl font-bold tracking-tight">个人中心</h2>
|
||||
<h2 className="text-2xl font-bold tracking-tight">
|
||||
{t("user_center")}
|
||||
</h2>
|
||||
<p className="text-muted-foreground">
|
||||
管理您的帐户设置并设置电子邮件首选项。
|
||||
{t("manage_account_settings_email_preferences")}
|
||||
</p>
|
||||
</div>
|
||||
<Separator className="my-6" />
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Separator } from "~/lib/ui/separator";
|
||||
import ProfileForm from "~/app/[local]/(manage)/user/[userId]/_components/profile-form";
|
||||
import { api } from "~/trpc/server";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
|
||||
export default async function SettingProfilePage({
|
||||
params: { userId },
|
||||
|
@ -8,14 +9,13 @@ export default async function SettingProfilePage({
|
|||
params: { userId: string };
|
||||
}) {
|
||||
const user = await api.user.getOne.query({ id: userId });
|
||||
const t = await getTranslations("user-[userId]");
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h3 className="text-lg font-medium">个人资料</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
设置你的名称和头像,需要重新登录后生效
|
||||
</p>
|
||||
<h3 className="text-lg font-medium">{t("profile")}</h3>
|
||||
<p className="text-sm text-muted-foreground">{t("set_name_avatar")}</p>
|
||||
</div>
|
||||
<Separator />
|
||||
<ProfileForm user={user} />
|
||||
|
|
|
@ -7,22 +7,26 @@ import {
|
|||
} from "~/lib/ui/dialog";
|
||||
import UpdatePasswordForm from "~/app/[local]/_components/update-password-form";
|
||||
import { Button } from "~/lib/ui/button";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
|
||||
export default function UpdatePasswordDialog({
|
||||
export default async function UpdatePasswordDialog({
|
||||
userId,
|
||||
type,
|
||||
}: {
|
||||
userId: string;
|
||||
type: "setup" | "reset";
|
||||
}) {
|
||||
const t = await getTranslations("global_update-password-dialog");
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button>{type === "reset" ? "更改密码" : "设置密码"}</Button>
|
||||
<Button>
|
||||
{type === "reset" ? t("change-password") : t("set-password")}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>更新密码</DialogTitle>
|
||||
<DialogTitle>{t("set-password")}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<UpdatePasswordForm userId={userId} type={type} />
|
||||
</DialogContent>
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
import { Input } from "~/lib/ui/input";
|
||||
import { Button } from "~/lib/ui/button";
|
||||
import React, { useMemo } from "react";
|
||||
import { useTranslations } from "use-intl";
|
||||
|
||||
const passwordStrengthRegex =
|
||||
/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d^@$!%*#?&]{6,16}$/;
|
||||
|
@ -38,6 +39,7 @@ export default function UpdatePasswordForm({
|
|||
userId: string;
|
||||
type: "setup" | "reset";
|
||||
}) {
|
||||
const t = useTranslations("global_update-password-form");
|
||||
const updatePasswordMutation = api.user.updatePassword.useMutation();
|
||||
const router = useRouter();
|
||||
|
||||
|
@ -47,7 +49,9 @@ export default function UpdatePasswordForm({
|
|||
}
|
||||
return updatePasswordFormSchema.and(
|
||||
z.object({
|
||||
originalPassword: z.string().min(1, "请输入原密码"),
|
||||
originalPassword: z
|
||||
.string()
|
||||
.min(1, t("please-enter-your-old-password")),
|
||||
}),
|
||||
);
|
||||
}, [type]);
|
||||
|
@ -80,7 +84,7 @@ export default function UpdatePasswordForm({
|
|||
name="originalPassword"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>原密码</FormLabel>
|
||||
<FormLabel>{t("old-password")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="password"
|
||||
|
@ -100,7 +104,7 @@ export default function UpdatePasswordForm({
|
|||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>密码</FormLabel>
|
||||
<FormLabel>{t("password")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
id="password"
|
||||
|
@ -120,7 +124,7 @@ export default function UpdatePasswordForm({
|
|||
name="confirmPassword"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>确认密码</FormLabel>
|
||||
<FormLabel>{t("confirm-password")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="password"
|
||||
|
@ -141,7 +145,7 @@ export default function UpdatePasswordForm({
|
|||
loading={updatePasswordMutation.isLoading}
|
||||
success={updatePasswordMutation.isSuccess}
|
||||
>
|
||||
保存
|
||||
{t("save")}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
Loading…
Reference in New Issue
Block a user