frontend phase 9

This commit is contained in:
hamid
2026-07-10 11:49:55 +03:30
parent cd6c2591a6
commit 40cc1d163b
49 changed files with 4130 additions and 20 deletions
@@ -14,13 +14,14 @@ const BASE = '/api/v1/booking_requests';
/**
* The b8 wire `BookingRequestDto` — identical to our app DTO minus the client-augmented `variantPrice`
* (REQ-013: the contract returns `variantLabel` + `variantPriceUnit` but no price).
* (REQ-013: the contract returns `variantLabel` + `variantPriceUnit` but no price) and `bookingId`
* (REQ-017: a `converted` request gives no way to reach the booking it became).
*/
type BookingRequestWireDto = Omit<BookingRequestDto, 'variantPrice'>;
type BookingRequestWireDto = Omit<BookingRequestDto, 'variantPrice' | 'bookingId'>;
/** Map the wire DTO to the app DTO, defaulting the not-yet-contracted `variantPrice` to `null`. */
/** Map the wire DTO to the app DTO, defaulting the not-yet-contracted fields to `null`. */
function toDto(wire: BookingRequestWireDto): BookingRequestDto {
return { ...wire, variantPrice: null };
return { ...wire, variantPrice: null, bookingId: null };
}
/**
@@ -36,6 +36,7 @@ function seedRow(overrides: Partial<BookingRequestDto>): BookingRequestDto {
return {
id,
status: 'pending_nurse_response',
bookingId: null,
nurseId: 1,
nurseName: 'مریم رضایی',
nurseRating: 4.9,
@@ -167,6 +168,7 @@ function buildFromContext(
return {
id,
status: 'pending_nurse_response',
bookingId: null,
nurseId: payload.nurseId,
nurseName: context?.nurseName ?? '',
nurseRating: context?.nurseRating ?? 0,
@@ -283,3 +285,20 @@ export const bookingRequestsMockApi: BookingRequestsApi = {
return updated;
},
};
/**
* Mock-only capture bridge (f9): the payment mock's stand-in for the server's webhook-confirm →
* `BookingFactory` step. Marks a paid request `converted` and stamps the client-augmented `bookingId`
* (REQ-017) so C5's terminal card and the checkout confirmation can deep-link the booking. NOT part of
* the `BookingRequestsApi` seam — no real endpoint does this from the client; only `services/payment`'s
* mock imports it.
*/
export function mockMarkBookingRequestConverted(id: number, bookingId: number): BookingRequestDto {
const dto = find(id);
if (dto.status !== 'accepted_awaiting_payment') {
throw new ApiError(409, 'Request is not awaiting payment', 'not_awaiting_payment');
}
const updated: BookingRequestDto = { ...dto, status: 'converted', bookingId };
store = store.map((row) => (row.id === id ? updated : row));
return updated;
}
@@ -59,10 +59,17 @@ export function isTerminalBookingRequestStatus(status: BookingRequestStatus): bo
* `variantPrice` is **client-augmented**: the contract DTO returns `variantLabel` + `variantPriceUnit`
* but no price (filed as REQ-013). The mock supplies it so the summary card can price the service; the
* real client leaves it `null` (the summary then hides the amount) until the field lands.
*
* `bookingId` is likewise **client-augmented** (filed as REQ-017): once a paid request converts, the b8
* DTO gives no way to reach the booking it became. The mock stamps it at capture so C5's `converted`
* card and the checkout confirmation can deep-link the booking; the real client leaves it `null` (those
* surfaces then fall back to the bookings list) until the field lands.
*/
export interface BookingRequestDto {
id: number;
status: BookingRequestStatus;
/** Client-augmented (REQ-017): the converted booking's id, or `null` until converted / on the real path. */
bookingId: number | null;
nurseId: number;
nurseName: string;
nurseRating: number;