feat(ui): i18n for user search modal

This commit is contained in:
吹雪 2026-06-10 12:02:45 +09:00
parent c084e10de9
commit 60f73e1eb6
3 changed files with 72 additions and 19 deletions

View file

@ -1,4 +1,5 @@
import { useState, useCallback } from "react";
import { useState, useCallback, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Modal, Form, Button, Select, Tooltip } from "antd";
import { UserAddOutlined } from "@ant-design/icons";
import debounce from "lodash/debounce";
@ -43,19 +44,32 @@ const UserSearchModal: React.FC<UserSearchModalProps> = ({
onCancel,
onSubmit,
accessToken,
title = "Add Team Member",
roles = [
{
label: "admin",
value: "admin",
description: "Admin role. Can create team keys, add members, and manage settings.",
},
{ label: "user", value: "user", description: "User role. Can view team info, but not manage it." },
],
title,
roles,
defaultRole = "user",
teamId,
}) => {
const { t } = useTranslation();
const [form] = Form.useForm<FormValues>();
const defaultRoles = useMemo(
() => [
{
label: t("commonComponents.userSearchModal.roleAdminLabel"),
value: "admin",
description: t("commonComponents.userSearchModal.roleAdminDescription"),
},
{
label: t("commonComponents.userSearchModal.roleUserLabel"),
value: "user",
description: t("commonComponents.userSearchModal.roleUserDescription"),
},
],
[t],
);
const effectiveRoles = roles ?? defaultRoles;
const effectiveTitle = title ?? t("commonComponents.userSearchModal.title");
const [userOptions, setUserOptions] = useState<UserOption[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [selectedField, setSelectedField] = useState<"user_email" | "user_id">("user_email");
@ -128,7 +142,14 @@ const UserSearchModal: React.FC<UserSearchModalProps> = ({
};
return (
<Modal title={title} open={isVisible} onCancel={handleClose} footer={null} width={800} maskClosable={!isSubmitting}>
<Modal
title={effectiveTitle}
open={isVisible}
onCancel={handleClose}
footer={null}
width={800}
maskClosable={!isSubmitting}
>
<Form<FormValues>
form={form}
onFinish={handleSubmit}
@ -139,11 +160,11 @@ const UserSearchModal: React.FC<UserSearchModalProps> = ({
role: defaultRole,
}}
>
<Form.Item label="Email" name="user_email" className="mb-4">
<Form.Item label={t("commonComponents.userSearchModal.emailLabel")} name="user_email" className="mb-4">
<Select
showSearch
className="w-full"
placeholder="Search by email"
placeholder={t("commonComponents.userSearchModal.searchByEmailPlaceholder")}
filterOption={false}
onSearch={(value) => handleSearch(value, "user_email")}
onSelect={(value, option) => handleSelect(value, option as UserOption)}
@ -154,13 +175,13 @@ const UserSearchModal: React.FC<UserSearchModalProps> = ({
/>
</Form.Item>
<div className="text-center mb-4">OR</div>
<div className="text-center mb-4">{t("commonComponents.userSearchModal.orDivider")}</div>
<Form.Item label="User ID" name="user_id" className="mb-4">
<Form.Item label={t("commonComponents.userSearchModal.userIdLabel")} name="user_id" className="mb-4">
<Select
showSearch
className="w-full"
placeholder="Search by user ID"
placeholder={t("commonComponents.userSearchModal.searchByUserIdPlaceholder")}
filterOption={false}
onSearch={(value) => handleSearch(value, "user_id")}
onSelect={(value, option) => handleSelect(value, option as UserOption)}
@ -170,9 +191,9 @@ const UserSearchModal: React.FC<UserSearchModalProps> = ({
/>
</Form.Item>
<Form.Item label="Member Role" name="role" className="mb-4">
<Form.Item label={t("commonComponents.userSearchModal.memberRoleLabel")} name="role" className="mb-4">
<Select defaultValue={defaultRole}>
{roles.map((role) => (
{effectiveRoles.map((role) => (
<Select.Option key={role.value} value={role.value}>
<Tooltip title={role.description}>
<span className="font-medium">{role.label}</span>
@ -185,7 +206,9 @@ const UserSearchModal: React.FC<UserSearchModalProps> = ({
<div className="text-right mt-4">
<Button type="primary" htmlType="submit" icon={<UserAddOutlined />} loading={isSubmitting}>
{isSubmitting ? "Adding..." : "Add Member"}
{isSubmitting
? t("commonComponents.userSearchModal.adding")
: t("commonComponents.userSearchModal.addMember")}
</Button>
</div>
</Form>

View file

@ -365,6 +365,21 @@
"teamDropdown": {
"placeholder": "Search or select a team",
"notFound": "No teams found"
},
"userSearchModal": {
"title": "Add Team Member",
"emailLabel": "Email",
"searchByEmailPlaceholder": "Search by email",
"orDivider": "OR",
"userIdLabel": "User ID",
"searchByUserIdPlaceholder": "Search by user ID",
"memberRoleLabel": "Member Role",
"roleAdminLabel": "admin",
"roleAdminDescription": "Admin role. Can create team keys, add members, and manage settings.",
"roleUserLabel": "user",
"roleUserDescription": "User role. Can view team info, but not manage it.",
"adding": "Adding...",
"addMember": "Add Member"
}
},
"common": {

View file

@ -365,6 +365,21 @@
"teamDropdown": {
"placeholder": "搜索或选择团队",
"notFound": "未找到团队"
},
"userSearchModal": {
"title": "添加团队成员",
"emailLabel": "邮箱",
"searchByEmailPlaceholder": "按邮箱搜索",
"orDivider": "或",
"userIdLabel": "用户 ID",
"searchByUserIdPlaceholder": "按用户 ID 搜索",
"memberRoleLabel": "成员角色",
"roleAdminLabel": "admin",
"roleAdminDescription": "管理员角色,可创建团队密钥、添加成员并管理设置。",
"roleUserLabel": "user",
"roleUserDescription": "普通用户角色,可查看团队信息,但无法管理。",
"adding": "添加中...",
"addMember": "添加成员"
}
},
"common": {