ui phase 7
This commit is contained in:
@@ -132,6 +132,11 @@ function toListItem(dto: BookingRequestDto, role: RequestRole): BookingRequestLi
|
||||
nurseResponseDeadlineAt: dto.nurseResponseDeadlineAt,
|
||||
paymentDeadlineAt: dto.paymentDeadlineAt,
|
||||
customerNotes: role === 'nurse' ? dto.customerNotes : null,
|
||||
// ui-phase-7 (REQ-050): the nurse inbox is decision-first — service + price on the row itself. The
|
||||
// real list DTO doesn't carry these yet; only the mock stamps them (the detail DTO always has them).
|
||||
variantLabel: dto.variantLabel,
|
||||
variantPrice: dto.variantPrice,
|
||||
variantPriceUnit: dto.variantPriceUnit,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
const MINUTES_PER_HOUR = 60;
|
||||
|
||||
/**
|
||||
* Humanized minutes-remaining copy above `CountdownTimer`'s coarse threshold («حدود ۳ ساعت» / «حدود ۲۵
|
||||
* دقیقه»). Shared by the customer C5 response countdown and the nurse inbox's urgency-tinted countdown
|
||||
* pill (ui-phase-7) — both count down the same `nurseResponseDeadlineAt`, so the humanized framing must
|
||||
* read identically in both places. `t` is the `booking` namespace translator (`countdown_about_hours`/
|
||||
* `countdown_about_minutes`).
|
||||
*/
|
||||
export function coarseResponseLabel(
|
||||
minutes: number,
|
||||
t: (key: string, values?: Record<string, number>) => string,
|
||||
): string {
|
||||
if (minutes >= MINUTES_PER_HOUR) {
|
||||
return t('countdown_about_hours', { hours: Math.round(minutes / MINUTES_PER_HOUR) });
|
||||
}
|
||||
return t('countdown_about_minutes', { minutes });
|
||||
}
|
||||
@@ -13,15 +13,21 @@ import type { BookingRequestStatus } from '../types';
|
||||
/**
|
||||
* The nurse incoming-requests inbox (`list?role=nurse`), defaulting to `pending_nurse_response`. Lightly
|
||||
* polls so newly-arrived requests appear without a manual refresh; every accept/reject invalidates this
|
||||
* list so an actioned request leaves the pending inbox immediately.
|
||||
* list so an actioned request leaves the pending inbox immediately. `options.enabled` (default `true`)
|
||||
* lets a multi-tab inbox (ui-phase-7) mount every status query up front without polling tabs the nurse
|
||||
* isn't currently viewing.
|
||||
*/
|
||||
export function useNurseRequestInbox(status: BookingRequestStatus | undefined = 'pending_nurse_response', page = 1) {
|
||||
export function useNurseRequestInbox(
|
||||
status: BookingRequestStatus | undefined = 'pending_nurse_response',
|
||||
page = 1,
|
||||
options?: { enabled?: boolean },
|
||||
) {
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const params = { role: 'nurse' as const, status, page, pageSize: BOOKING_REQUEST_PAGE_SIZE };
|
||||
return useQuery({
|
||||
queryKey: bookingRequestKeys.nurseInbox(params),
|
||||
queryFn: () => bookingRequestsApi.list(params),
|
||||
enabled: isAuthenticated,
|
||||
enabled: isAuthenticated && (options?.enabled ?? true),
|
||||
staleTime: BOOKING_REQUEST_STALE_TIME,
|
||||
gcTime: BOOKING_REQUEST_GC_TIME,
|
||||
refetchInterval: BOOKING_REQUEST_POLL_MS,
|
||||
|
||||
@@ -129,6 +129,14 @@ export interface BookingRequestListItem {
|
||||
paymentDeadlineAt: string | null;
|
||||
/** Nurse view only (stage-1 plaintext); `null` in the customer inbox. */
|
||||
customerNotes: string | null;
|
||||
/**
|
||||
* Client-augmented (ui-phase-7, REQ-050) — the list DTO carries no variant fields today. `undefined` on
|
||||
* the real path until the field lands; the nurse-inbox card renders the decision-first headline when
|
||||
* present and degrades to the patient-name headline otherwise (mock-tolerant, never fetched per-row).
|
||||
*/
|
||||
variantLabel?: string | null;
|
||||
variantPrice?: string | null;
|
||||
variantPriceUnit?: PriceUnit | null;
|
||||
}
|
||||
|
||||
/** The `booking_requests/create` body (contract). Money-free; ids come from search/patients/addresses. */
|
||||
|
||||
Reference in New Issue
Block a user