refinement phase 4
This commit is contained in:
@@ -25,23 +25,34 @@ async function orNull<T>(promise: Promise<T>): Promise<T | null> {
|
||||
}
|
||||
}
|
||||
|
||||
// The wire DTOs carry no avatar/name yet (REQ-006/007); reads default the augmented fields.
|
||||
function toNurseProfile(dto: NurseProfileDto): NurseProfile {
|
||||
return { ...dto, avatarUrl: null };
|
||||
/** REQ-006 (delivered): both profile DTOs now carry `avatarUrl`; the customer DTO also carries `preferredLanguage`. */
|
||||
interface NurseProfileWire extends NurseProfileDto {
|
||||
avatarUrl: string | null;
|
||||
}
|
||||
function toCustomerProfile(dto: CustomerProfileDto): CustomerProfile {
|
||||
return { ...dto, firstName: null, lastName: null, preferredLanguage: null };
|
||||
interface CustomerProfileWire extends CustomerProfileDto {
|
||||
avatarUrl: string | null;
|
||||
preferredLanguage: string | null;
|
||||
}
|
||||
|
||||
function toNurseProfile(dto: NurseProfileWire): NurseProfile {
|
||||
return { ...dto, avatarUrl: dto.avatarUrl ?? null };
|
||||
}
|
||||
// The customer name lives on `/me` (REQ-007 design), not on `CustomerProfileDto` — the profile screen
|
||||
// sources first/last name from `useMe`. Here we carry the served `preferredLanguage`; name stays null.
|
||||
function toCustomerProfile(dto: CustomerProfileWire): CustomerProfile {
|
||||
return { ...dto, firstName: null, lastName: null, preferredLanguage: dto.preferredLanguage ?? null };
|
||||
}
|
||||
|
||||
/**
|
||||
* Real HTTP implementation of the ProfilesApi seam (b3 action-style routes). Selected once
|
||||
* USE_PROFILES_MOCK is false and the avatar/name gaps land. `uploadAvatar` has no route yet
|
||||
* (REQ-006) and the JSON-only fetch layer can't send multipart — it stays mock-only.
|
||||
* Real HTTP implementation of the ProfilesApi seam (b3 action-style routes). PRIMARY once
|
||||
* USE_PROFILES_MOCK is false (refinement-phase-4; REQ-006/007 delivered). Avatar upload posts multipart
|
||||
* to the b3 `nurse_profiles/avatar` route (the JSON-only default is bypassed for `FormData` bodies —
|
||||
* see `lib/api/client.ts`); the customer name/language reach the server via the upsert body.
|
||||
*/
|
||||
export const profilesClientApi: ProfilesApi = {
|
||||
getCustomerProfile: async () =>
|
||||
orNull(
|
||||
clientFetch<ApiEnvelope<CustomerProfileDto>>(`${BASE}/customer_profiles/me`).then((env) =>
|
||||
clientFetch<ApiEnvelope<CustomerProfileWire>>(`${BASE}/customer_profiles/me`).then((env) =>
|
||||
toCustomerProfile(unwrap(env)),
|
||||
),
|
||||
),
|
||||
@@ -49,11 +60,15 @@ export const profilesClientApi: ProfilesApi = {
|
||||
upsertCustomerProfile: async (input: UpsertCustomerProfileInput) =>
|
||||
toCustomerProfile(
|
||||
unwrap(
|
||||
await clientFetch<ApiEnvelope<CustomerProfileDto>>(`${BASE}/customer_profiles/upsert`, {
|
||||
await clientFetch<ApiEnvelope<CustomerProfileWire>>(`${BASE}/customer_profiles/upsert`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
defaultEmergencyContactName: input.defaultEmergencyContactName,
|
||||
defaultEmergencyContactPhone: input.defaultEmergencyContactPhone,
|
||||
// REQ-007 (delivered): name + preferred language are accepted on the upsert command.
|
||||
firstName: input.firstName ?? null,
|
||||
lastName: input.lastName ?? null,
|
||||
preferredLanguage: input.preferredLanguage ?? null,
|
||||
}),
|
||||
}),
|
||||
),
|
||||
@@ -61,13 +76,13 @@ export const profilesClientApi: ProfilesApi = {
|
||||
|
||||
getNurseProfile: async () =>
|
||||
orNull(
|
||||
clientFetch<ApiEnvelope<NurseProfileDto>>(`${BASE}/nurse_profiles/me`).then((env) => toNurseProfile(unwrap(env))),
|
||||
clientFetch<ApiEnvelope<NurseProfileWire>>(`${BASE}/nurse_profiles/me`).then((env) => toNurseProfile(unwrap(env))),
|
||||
),
|
||||
|
||||
upsertNurseProfile: async (input: UpsertNurseProfileInput) =>
|
||||
toNurseProfile(
|
||||
unwrap(
|
||||
await clientFetch<ApiEnvelope<NurseProfileDto>>(`${BASE}/nurse_profiles/upsert`, {
|
||||
await clientFetch<ApiEnvelope<NurseProfileWire>>(`${BASE}/nurse_profiles/upsert`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
bio: input.bio,
|
||||
@@ -80,7 +95,16 @@ export const profilesClientApi: ProfilesApi = {
|
||||
),
|
||||
),
|
||||
|
||||
uploadAvatar: async (): Promise<AvatarUploadResult> => {
|
||||
throw new ApiError(501, 'Avatar upload has no backend route yet (REQ-006); served by the mock.');
|
||||
// REQ-006 (delivered): only the nurse profile screen uploads an avatar today; it persists immediately
|
||||
// via the dedicated multipart route and the returned URL is echoed for display + read back on reload.
|
||||
uploadAvatar: async (file: File): Promise<AvatarUploadResult> => {
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
return unwrap(
|
||||
await clientFetch<ApiEnvelope<AvatarUploadResult>>(`${BASE}/nurse_profiles/avatar`, {
|
||||
method: 'POST',
|
||||
body: form,
|
||||
}),
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user