refinement phase 4
This commit is contained in:
@@ -24,11 +24,17 @@ interface NurseReviewsWire {
|
||||
reviews: Paginated<ReviewListItem>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wire `ModerationQueueItemDto`. Per the b14 contract it does **not** carry `tagCodes` (REQ-037 — the admin
|
||||
* card can't show the review's tags); the client defaults it to `[]` on map.
|
||||
*/
|
||||
type ModerationQueueItemWire = Omit<ModerationQueueItem, 'tagCodes'>;
|
||||
/** Wire `MyReviewDto` (REQ-026) — keys the moderation state as `moderationStatus` (`'none'` when unreviewed). */
|
||||
interface MyReviewDto {
|
||||
moderationStatus: MyReviewState['status'];
|
||||
rating: number | null;
|
||||
body: string | null;
|
||||
tagCodes: string[];
|
||||
createdAt: string | null;
|
||||
}
|
||||
|
||||
/** Wire `ModerationQueueItemDto` — carries `tagCodes` since REQ-037 (delivered in refinement-phase-3). */
|
||||
type ModerationQueueItemWire = ModerationQueueItem;
|
||||
|
||||
/**
|
||||
* Real HTTP implementation of the `ReviewsApi` seam (b14 contract `dev/contracts/domains/reviews-records.md`,
|
||||
@@ -57,14 +63,30 @@ export const reviewsClientApi: ReviewsApi = {
|
||||
return { aggregate: wire.aggregate, reviews: wire.reviews };
|
||||
},
|
||||
|
||||
// REQ-026: proposed owner-scoped read (no wire endpoint yet). 404s until delivered — never called while
|
||||
// the domain is mock-primary. Kept symmetric so the swap stays a one-line config flip.
|
||||
getReviewEligibility: async (bookingId: number): Promise<ReviewEligibility> =>
|
||||
unwrap(await clientFetch<ApiEnvelope<ReviewEligibility>>(`${API}/bookings/${bookingId}/review_eligibility`)),
|
||||
// REQ-026 (delivered): owner-scoped eligibility read. Wire `reason` is nullable; normalise to `undefined`.
|
||||
getReviewEligibility: async (bookingId: number): Promise<ReviewEligibility> => {
|
||||
const wire = unwrap(
|
||||
await clientFetch<ApiEnvelope<{ canReview: boolean; reason: ReviewEligibility['reason'] | null }>>(
|
||||
`${API}/bookings/${bookingId}/review_eligibility`,
|
||||
),
|
||||
);
|
||||
return { canReview: wire.canReview, reason: wire.reason ?? undefined };
|
||||
},
|
||||
|
||||
// REQ-026: proposed owner-scoped read of the caller's own review for this booking.
|
||||
getMyReviewForBooking: async (bookingId: number): Promise<MyReviewState> =>
|
||||
unwrap(await clientFetch<ApiEnvelope<MyReviewState>>(`${API}/bookings/${bookingId}/my_review`)),
|
||||
// REQ-026 (delivered): the caller's own review for this booking + its moderation state. The wire dto keys
|
||||
// the state as `moderationStatus` (incl. `'none'` when unreviewed); the client model calls it `status`.
|
||||
getMyReviewForBooking: async (bookingId: number): Promise<MyReviewState> => {
|
||||
const wire = unwrap(
|
||||
await clientFetch<ApiEnvelope<MyReviewDto>>(`${API}/bookings/${bookingId}/my_review`),
|
||||
);
|
||||
return {
|
||||
status: wire.moderationStatus,
|
||||
rating: wire.rating,
|
||||
body: wire.body,
|
||||
tagCodes: wire.tagCodes ?? [],
|
||||
createdAt: wire.createdAt,
|
||||
};
|
||||
},
|
||||
|
||||
createReview: async (bookingId: number, body: CreateReviewRequest): Promise<SubmitReviewResult> =>
|
||||
unwrap(
|
||||
@@ -84,8 +106,8 @@ export const reviewsClientApi: ReviewsApi = {
|
||||
`${API}/admin/reviews/moderation_queue?${query.toString()}`,
|
||||
),
|
||||
);
|
||||
// REQ-037: the wire dto omits tagCodes — default to [] so the admin card renders without them.
|
||||
return { ...wire, items: wire.items.map((item) => ({ ...item, tagCodes: [] })) };
|
||||
// REQ-037 (delivered): the wire dto carries tagCodes; default to [] only if the server omits it.
|
||||
return { ...wire, items: wire.items.map((item) => ({ ...item, tagCodes: item.tagCodes ?? [] })) };
|
||||
},
|
||||
|
||||
moderateReview: async (
|
||||
|
||||
Reference in New Issue
Block a user