The owner had no edit entry anywhere once /people replaced the settings chart pane. 本人 now gets 编辑 with the same form; the save goes through PATCH /api/account via a shared lib/self-profile-save.ts that the home onboarding also uses. The dead saveProfile is removed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
81 lines
3.5 KiB
TypeScript
81 lines
3.5 KiB
TypeScript
import { resolveAyanamsa } from "./ayanamsa.ts";
|
|
import { applyPersistedBirthTime, birthTimePersistenceValues } from "./birth-time-intake-model.ts";
|
|
import { readChartBirthFingerprint } from "./chart-birth-truth.ts";
|
|
import { selectedBirthPlace } from "./home-profile.ts";
|
|
import type { Profile } from "./home-types.ts";
|
|
import type { ProfileGender } from "./profile-gender.ts";
|
|
|
|
/**
|
|
* The owner's own profile write (`PATCH /api/account`), shared by the home
|
|
* onboarding and the 星盘档案 edit view (TASK-self-edit-avatar-menu-20260928
|
|
* S1, BUG-1081). The owner is never a `chart_profiles` row; every birth-data
|
|
* save goes through the account route, which checks `birth_time_source` and
|
|
* derives the birth-time status on the server.
|
|
*
|
|
* Birth-data saves never carry `gender` (TASK-consult-gender-optional): the
|
|
* owner's gender is its own one-field PATCH, so a birth-data save can never
|
|
* clear it.
|
|
*/
|
|
export function selfProfilePatchBody(nextProfile: Profile) {
|
|
const birthPlace = selectedBirthPlace(nextProfile);
|
|
return {
|
|
name: nextProfile.name.trim() || null,
|
|
birth_date: nextProfile.date || null,
|
|
...birthTimePersistenceValues(nextProfile),
|
|
country_code: nextProfile.countryCode,
|
|
province_code: nextProfile.provinceCode || null,
|
|
city_code: nextProfile.cityCode || null,
|
|
district_code: nextProfile.districtCode || null,
|
|
birth_place_label: nextProfile.birthPlaceLabel || null,
|
|
birth_place_type: nextProfile.birthPlaceType || null,
|
|
birth_place_provider: nextProfile.birthPlaceProvider || null,
|
|
birth_place_provider_id: nextProfile.birthPlaceProviderId || null,
|
|
latitude: birthPlace?.lat ?? null,
|
|
longitude: birthPlace?.lon ?? null,
|
|
timezone_id: nextProfile.timezoneId || null,
|
|
timezone_offset: birthPlace?.tz ?? null,
|
|
timezone_source: nextProfile.timezoneSource || null,
|
|
ayanamsa: resolveAyanamsa(nextProfile),
|
|
};
|
|
}
|
|
|
|
export type SelfProfileSaved = Readonly<{
|
|
/** The draft with the birth-time truth the server returned applied. */
|
|
profile: Profile;
|
|
/** The chart page's `profileFingerprint` of the saved row, when the route returned one. */
|
|
fingerprint: string | null;
|
|
}>;
|
|
|
|
type Fetch = typeof fetch;
|
|
|
|
export async function saveSelfProfile(nextProfile: Profile, fetchImpl: Fetch = fetch): Promise<SelfProfileSaved> {
|
|
const response = await fetchImpl("/api/account", {
|
|
method: "PATCH",
|
|
credentials: "same-origin",
|
|
headers: { "content-type": "application/json" },
|
|
body: JSON.stringify(selfProfilePatchBody(nextProfile)),
|
|
});
|
|
const payload = await response.json().catch(() => null) as {
|
|
error?: string;
|
|
birthTime?: unknown;
|
|
chartBirth?: { fingerprint?: unknown };
|
|
} | null;
|
|
if (!response.ok) {
|
|
throw new Error(payload?.error || "账户资料暂时无法保存。");
|
|
}
|
|
const savedProfile = applyPersistedBirthTime(nextProfile, payload?.birthTime);
|
|
return { profile: savedProfile, fingerprint: readChartBirthFingerprint(payload) };
|
|
}
|
|
|
|
/** The owner's optional gender, on its own; null clears it. */
|
|
export async function saveSelfGender(gender: ProfileGender | null, fetchImpl: Fetch = fetch): Promise<void> {
|
|
const response = await fetchImpl("/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 || "性别没保存上,再试一次。");
|
|
}
|