/** * When true, the tickets domain is served by the in-memory mock (`apis/mockApi.ts`) behind the `TicketsApi` * seam. * * **Mock is primary this phase.** b15 serves the ticket endpoints (open / list / thread / message), and the * real `clientApi.ts` maps them 1:1 — but the ticket screens depend on **inputs that are themselves * mock-primary** (the f8 bookings a coordination ticket links to only exist client-side under the bookings * mock), and the wire summary lacks `unreadCount`/`lastMessageAt` (**REQ-028**). So the mock is the primary * source: it seeds realistic tickets/threads **with no internal messages** (mimicking the server's user-view * `is_internal` stripping — it even stores an internal admin note that the user view drops, so the * no-leak test is demonstrable), supports the optimistic append, and makes a booking-linked coordination * ticket reachable. Flip to `false` once the upstreams are real — no hook/component change (only the seam * selection in `apis/index.ts`). */ export const USE_TICKETS_MOCK = false; /** Inbox page size (api-conventions `pageSize`, default 50 / max 100). */ export const TICKETS_PAGE_SIZE = 20; /** * The inbox list moves at human speed — a moderate `staleTime` avoids refetching on every revisit but a * mutation (open ticket / post message) invalidates it so a new ticket / new activity shows without a manual * refresh. The **thread is short-lived** (an active conversation) so it revalidates more eagerly. */ export const TICKETS_LIST_STALE_TIME = 30 * 1000; export const TICKET_THREAD_STALE_TIME = 15 * 1000; export const TICKETS_GC_TIME = 5 * 60 * 1000; /** * Poll the open thread while it's mounted (§3.2) — TanStack Query only polls while the query has an * active observer, so this is automatically scoped to the thread screen. Proportionate to a support * conversation, not a real-time chat; SSE can replace this later behind the same query. */ export const TICKET_THREAD_REFETCH_INTERVAL = 15 * 1000; /** * Photo-attachment affordance capability gate (§3.3) — the composer's attachment button is designed but * renders only when this is on. Default **off**: the object-storage linkage for ticket messages is a * backend gap (REQ-060); flip once that contract lands — no component change beyond this flag. */ export const TICKETS_ATTACHMENTS_ENABLED = false; /** The admin global queue is a live worklist — a short stale window keeps it fresh without hammering. */ export const ADMIN_TICKETS_LIST_STALE_TIME = 20 * 1000; /** * Ticket lifecycle controls (close/reopen/assign) capability gate — mirrors the `TICKETS_ATTACHMENTS_ENABLED` * pattern above. Default **off**: the backend has no close/reopen/assign routes yet (REQ-063), so the * real-path controls stay hidden rather than pointing at a route that would 404. Flip once the endpoints * land — no component change beyond this flag. */ export const TICKET_LIFECYCLE_ENABLED = false; /** * DEV-ONLY trigger for the optimistic-send **failure** path (phase §7 step 2): posting this exact message * body makes the mock throw a `500` so a human can watch the bubble roll back, the draft stay in the * composer, and the retry succeed. Never a product string. */ export const MOCK_SEND_FAIL_SENTINEL = '/fail'; /** * Stable per-role "me" ids for the **mock** world (the real path uses the authenticated `/me` id). The mock * seeds the customer's / nurse's / support's messages with these sender ids; `useTicket` passes * `currentUser?.id ?? MOCK_VIEWER_USER_ID[actorRole]` so a message renders as **mine** in whichever app is * viewing (customer app → the customer's bubbles are mine; nurse app → the nurse's are). The fallback only * fires under mock auth (no `/me` id); on the real path the authenticated id wins and this is dead weight. */ export const MOCK_VIEWER_USER_ID: Record<'customer' | 'nurse' | 'admin', number> = { customer: 7001, nurse: 7015, admin: 7003, };