Phase6c: Optional Company contact name
All checks were successful
Build and Push / build (push) Successful in 1m40s
All checks were successful
Build and Push / build (push) Successful in 1m40s
This commit is contained in:
@@ -528,3 +528,102 @@ export async function registerCustomer(params: {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// v2 User API — profile updates (Phase 6 fix5)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update a human user's profile (first name + last name). Returns
|
||||
* the new `details.changeDate` from ZITADEL so the caller can
|
||||
* confirm the write landed.
|
||||
*
|
||||
* The v2 user service endpoint is technically a PUT but accepts
|
||||
* partial bodies — only `profile.givenName` and `profile.familyName`
|
||||
* are sent. ZITADEL preserves email, password, and other fields
|
||||
* across the call (verified empirically in stripe-node#7786 and
|
||||
* documented in v2.63+ of zitadel-server).
|
||||
*
|
||||
* `displayName` is intentionally NOT sent. ZITADEL recomputes it
|
||||
* from givenName + familyName when not provided, which is what we
|
||||
* want — keeping displayName as a frozen value would let it drift
|
||||
* out of sync with the name parts on subsequent edits.
|
||||
*
|
||||
* Auth: the portal's service-account PAT (ZITADEL_SA_PAT). The PAT
|
||||
* must have user-write permission in the user's resource org.
|
||||
* Today portal-zitadel-sa-pat already has user-write for
|
||||
* createHumanUser etc. — same scope covers this.
|
||||
*/
|
||||
export interface UpdateHumanUserProfileResult {
|
||||
changeDate: string;
|
||||
/** ZITADEL recomputes this from given+family unless overridden. */
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
export async function updateHumanUserProfile(params: {
|
||||
userId: string;
|
||||
givenName: string;
|
||||
familyName: string;
|
||||
}): Promise<UpdateHumanUserProfileResult> {
|
||||
const path = `/v2/users/human/${encodeURIComponent(params.userId)}`;
|
||||
type ZitadelUpdateResponse = {
|
||||
details?: { changeDate?: string };
|
||||
};
|
||||
await zitadelFetch<ZitadelUpdateResponse>(path, "PUT", {
|
||||
profile: {
|
||||
givenName: params.givenName,
|
||||
familyName: params.familyName,
|
||||
},
|
||||
});
|
||||
// Re-fetch the user so we can return the canonical displayName
|
||||
// (ZITADEL computes "Given Family" itself; matching what NextAuth
|
||||
// sees in the next sign-in claim).
|
||||
const detail = await getHumanUserDetail(params.userId);
|
||||
return {
|
||||
changeDate: new Date().toISOString(),
|
||||
displayName: detail.displayName,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a human user's current profile (given/family/display name +
|
||||
* email). Used by the settings page to populate the form and by the
|
||||
* update helper above to read back the computed displayName.
|
||||
*/
|
||||
export interface HumanUserDetail {
|
||||
userId: string;
|
||||
givenName: string;
|
||||
familyName: string;
|
||||
displayName: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export async function getHumanUserDetail(
|
||||
userId: string
|
||||
): Promise<HumanUserDetail> {
|
||||
type ZitadelGetUserResponse = {
|
||||
user?: {
|
||||
userId?: string;
|
||||
human?: {
|
||||
profile?: {
|
||||
givenName?: string;
|
||||
familyName?: string;
|
||||
displayName?: string;
|
||||
};
|
||||
email?: { email?: string };
|
||||
};
|
||||
};
|
||||
};
|
||||
const response = await zitadelFetch<ZitadelGetUserResponse>(
|
||||
`/v2/users/${encodeURIComponent(userId)}`,
|
||||
"GET"
|
||||
);
|
||||
const human = response.user?.human;
|
||||
return {
|
||||
userId: response.user?.userId ?? userId,
|
||||
givenName: human?.profile?.givenName ?? "",
|
||||
familyName: human?.profile?.familyName ?? "",
|
||||
displayName: human?.profile?.displayName ?? "",
|
||||
email: human?.email?.email ?? "",
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user