;
};
export function ProfilePanel({
@@ -26,7 +20,6 @@ export function ProfilePanel({
avatarNotice,
accountError,
persistAvatar,
- persistGender,
}: ProfilePanelProps) {
return (
<>
@@ -77,40 +70,6 @@ export function ProfilePanel({
登录邮箱{account.user.email || "尚未读取邮箱"}
- {persistGender ? : null}
>
);
}
-
-/** 本人的性别(选填): saved as soon as a choice is made, like the avatar palette. */
-function OwnerGenderSection({
- value,
- persistGender,
-}: {
- readonly value: ProfileGender | null;
- readonly persistGender: (gender: ProfileGender | null) => Promise;
-}) {
- const [saving, setSaving] = useState(false);
- const [notice, setNotice] = useState("");
- const [error, setError] = useState("");
- async function choose(gender: ProfileGender | null) {
- setSaving(true);
- setNotice("");
- setError("");
- try {
- await persistGender(gender);
- setNotice("已保存。");
- } catch (caught) {
- setError(caught instanceof Error && caught.message ? caught.message : "性别没保存上,再试一次。");
- } finally {
- setSaving(false);
- }
- }
- return (
-
- void choose(gender)} />
- {notice ? {notice}
: null}
- {error ? {error}
: null}
-
- );
-}
diff --git a/frontend/src/hooks/use-profile-onboarding.ts b/frontend/src/hooks/use-profile-onboarding.ts
index 41e507a5..521cdb39 100644
--- a/frontend/src/hooks/use-profile-onboarding.ts
+++ b/frontend/src/hooks/use-profile-onboarding.ts
@@ -29,7 +29,6 @@ import {
readProfile,
selectedBirthPlace,
} from "@/lib/home-profile";
-import { withSavedGender, type ProfileGender } from "@/lib/profile-gender";
import { saveSelfProfile } from "@/lib/self-profile-save";
import { createStartGreeting } from "@/lib/starter-greeting";
import { clearHomeWarmSnapshot } from "@/lib/home-warm-snapshot";
@@ -194,26 +193,6 @@ export function useProfileOnboarding(params: ProfileOnboardingParams) {
}
}
- /**
- * The owner's optional gender (设置 → 个人资料). A PATCH of this one field:
- * birth-data saves never send it, so they can never clear it.
- */
- async function persistGender(gender: ProfileGender | null): Promise {
- if (!account) throw new Error("账户尚未加载完成");
- const response = await fetch("/api/account", {
- method: "PATCH",
- credentials: "same-origin",
- headers: { "content-type": "application/json" },
- body: JSON.stringify({ gender }),
- });
- const payload = await response.json().catch(() => null) as { error?: string } | null;
- if (!response.ok) throw new Error(payload?.error || "性别没保存上,再试一次。");
- const apply = (current: Profile): Profile => ({ ...current, gender });
- setProfile(apply);
- setProfileDraft(apply);
- setAccount((current) => current ? { ...current, profile: withSavedGender(current.profile, gender) } : current);
- }
-
async function persistProfile(nextProfile: Profile): Promise {
if (!account) throw new Error("账户尚未加载完成");
if (process.env.NODE_ENV === "development" && uiPreview.current) return nextProfile;
@@ -384,7 +363,6 @@ export function useProfileOnboarding(params: ProfileOnboardingParams) {
openAccountDialog,
closeAccountDialog,
persistAvatar,
- persistGender,
persistProfile,
assessSavedBirthTime,
saveOnboardingName,
diff --git a/frontend/src/lib/profile-gender.ts b/frontend/src/lib/profile-gender.ts
index 1c7ab278..f9d58b3b 100644
--- a/frontend/src/lib/profile-gender.ts
+++ b/frontend/src/lib/profile-gender.ts
@@ -35,9 +35,3 @@ export function profileGenderLabel(value: unknown): string {
const gender = parseProfileGender(value);
return gender ? PROFILE_GENDER_LABELS[gender] : PROFILE_GENDER_EMPTY_LABEL;
}
-
-/** The account's raw profile object with the saved gender (null = not filled). */
-export function withSavedGender(profile: unknown, gender: ProfileGender | null): Record {
- const base = profile && typeof profile === "object" && !Array.isArray(profile) ? profile as Record : {};
- return { ...base, gender };
-}
diff --git a/frontend/tests/profile-gender-ui-20260927.test.tsx b/frontend/tests/profile-gender-ui-20260927.test.tsx
index cd41ae80..4e505898 100644
--- a/frontend/tests/profile-gender-ui-20260927.test.tsx
+++ b/frontend/tests/profile-gender-ui-20260927.test.tsx
@@ -1,5 +1,5 @@
// TASK-consult-gender-optional-20260927 T2: optional gender radio (女 / 男 / 不填)
-// in the people-archive edit form and the owner's 个人资料, one explanatory
+// in the people-archive edit form (the only place since 2026-09-30), one explanatory
// line, and the detail card shows the stored value (未填 when empty).
// Fictional people only (AGENTS §8).
import assert from "node:assert/strict";
@@ -125,16 +125,24 @@ test("detail card: 性别 shows the stored value, 未填 when empty; 本人 edit
});
test("个人资料: the owner's gender saves on its own and birth-data saves never send it", () => {
+ // 原值: 个人资料 rendered the 女 / 男 / 不填 radios (["女:true", "男:false", "不填:false"]) plus the hint, and
+ // use-profile-onboarding's persistGender sent the one-field PATCH
+ // 新值: 个人资料 has no gender control; the one-field PATCH is saveSelfGender, called from the people archive's self edit
+ // 原因: 产品 2026-09-30「性别应该在档案里设置而不是在个人资料的账户里设置」——两个入口删一个(BUG-1119)
const account = { user: { id: "u", email: "fictional@example.invalid" }, avatar: null } as unknown as Account;
const panel = renderToStaticMarkup(
{}} persistGender={async () => {}} />,
+ accountError="" persistAvatar={() => {}} />,
);
- assert.deepEqual(radios(panel), ["女:true", "男:false", "不填:false"]);
- assert.ok(panel.includes(PROFILE_GENDER_HINT));
+ assert.deepEqual(radios(panel), []);
+ assert.equal(panel.includes(PROFILE_GENDER_HINT), false);
+ const people = readFileSync(new URL("../src/components/people/people-page.tsx", import.meta.url), "utf8");
+ assert.match(people, /await saveSelfGender\(gender\)/);
+ const selfSave = readFileSync(new URL("../src/lib/self-profile-save.ts", import.meta.url), "utf8");
+ const saveGender = selfSave.slice(selfSave.indexOf("export async function saveSelfGender"));
+ assert.match(saveGender, /body: JSON\.stringify\(\{ gender \}\)/);
const hook = readFileSync(new URL("../src/hooks/use-profile-onboarding.ts", import.meta.url), "utf8");
- const persistGender = hook.slice(hook.indexOf("async function persistGender"), hook.indexOf("async function persistProfile"));
- assert.match(persistGender, /body: JSON\.stringify\(\{ gender \}\)/);
+ assert.equal(/persistGender/.test(hook), false, "no second gender entry in the home hook");
const persistProfile = hook.slice(hook.indexOf("async function persistProfile"), hook.indexOf("async function assessSavedBirthTime"));
assert.equal(/gender/.test(persistProfile), false, "onboarding and birth-data saves do not carry gender");
const onboarding = readFileSync(new URL("../src/components/home-onboarding-shell.tsx", import.meta.url), "utf8");