@natoe/colab 0.1.27 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +109 -19
- package/dist/index.d.ts +109 -19
- package/dist/index.js +171 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +170 -57
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -118,17 +118,51 @@ interface PatientData {
|
|
|
118
118
|
labName?: string;
|
|
119
119
|
bodyParts?: string[];
|
|
120
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* What a thread is about — and, crucially, what it is SCOPED to.
|
|
123
|
+
*
|
|
124
|
+
* - `case` — the discussion about one clinical order. Scoped to an order,
|
|
125
|
+
* so `orderId` is always set. Lab, radiologist, physician, admin.
|
|
126
|
+
* - `help_lab` — an imaging centre's help channel with Natoe support. Scoped to
|
|
127
|
+
* the LAB, not to any case: it has NO `orderId`, it outlives
|
|
128
|
+
* every order, and there is exactly one per imaging centre.
|
|
129
|
+
*
|
|
130
|
+
* `help_lab` was briefly modelled as per-case (one help thread per order). It is
|
|
131
|
+
* now per-lab, so support gets one continuous thread with each imaging centre
|
|
132
|
+
* rather than N short-lived ones scattered across cases. A case can still be
|
|
133
|
+
* referenced from inside the channel; it just no longer scopes it.
|
|
134
|
+
*
|
|
135
|
+
* Isolation — who can see a help channel — is enforced by the backend's
|
|
136
|
+
* participant seeding, never by anything in this package. Treat this as a label
|
|
137
|
+
* for rendering and for addressing the right thread, not as a security boundary.
|
|
138
|
+
*
|
|
139
|
+
* Optional everywhere, defaulting to `case`, so callers written before help
|
|
140
|
+
* channels existed keep their exact previous behaviour.
|
|
141
|
+
*/
|
|
142
|
+
type ConversationKind = 'case' | 'help_lab';
|
|
143
|
+
declare function isHelpKind(kind?: ConversationKind | string): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* True when a thread is scoped to an order and therefore has patient context to
|
|
146
|
+
* render. Prefer this over testing `orderId` directly: a help channel has no
|
|
147
|
+
* order, so every patient-shaped affordance must be skipped for it.
|
|
148
|
+
*/
|
|
149
|
+
declare function isCaseKind(kind?: ConversationKind | string): boolean;
|
|
121
150
|
interface Conversation {
|
|
122
151
|
id: string;
|
|
123
|
-
|
|
152
|
+
/** Absent on a help channel — that thread belongs to a lab, not an order. */
|
|
153
|
+
orderId?: string;
|
|
154
|
+
/** Set only on a help channel: the imaging centre that owns it. */
|
|
155
|
+
labUserId?: string;
|
|
124
156
|
name: string;
|
|
157
|
+
kind?: ConversationKind;
|
|
125
158
|
picture?: string;
|
|
126
159
|
participants: Participant[];
|
|
127
160
|
lastMessage?: Message;
|
|
128
161
|
unreadCount: number;
|
|
129
162
|
createdAt: string;
|
|
130
163
|
updatedAt: string;
|
|
131
|
-
/** Denormalized patient data snapshot — lets UI render without extra fetch
|
|
164
|
+
/** Denormalized patient data snapshot — lets UI render without extra fetch.
|
|
165
|
+
* Always absent on a help channel: there is no patient. */
|
|
132
166
|
patientSnapshot?: PatientData;
|
|
133
167
|
/** Currently pinned messages (max 3) */
|
|
134
168
|
pinnedMessages?: Message[];
|
|
@@ -139,8 +173,13 @@ interface Conversation {
|
|
|
139
173
|
*/
|
|
140
174
|
interface ConversationListItem$1 {
|
|
141
175
|
id: string;
|
|
142
|
-
orderId
|
|
176
|
+
/** Absent on a help channel — see `Conversation.orderId`. */
|
|
177
|
+
orderId?: string;
|
|
178
|
+
labUserId?: string;
|
|
143
179
|
name: string;
|
|
180
|
+
/** Lets the inbox render the lab's help channel distinctly from its case
|
|
181
|
+
* threads — they appear as separate rows. */
|
|
182
|
+
kind?: ConversationKind;
|
|
144
183
|
picture?: string;
|
|
145
184
|
unreadCount: number;
|
|
146
185
|
lastMessage?: Message;
|
|
@@ -154,6 +193,7 @@ interface ConversationListItem$1 {
|
|
|
154
193
|
interface ConversationPreview {
|
|
155
194
|
conversationId: string;
|
|
156
195
|
orderId: string;
|
|
196
|
+
kind?: ConversationKind;
|
|
157
197
|
messageCount: number;
|
|
158
198
|
unreadCount: number;
|
|
159
199
|
/** Last N messages (typically 5) for inline display */
|
|
@@ -163,7 +203,9 @@ interface ConversationPreview {
|
|
|
163
203
|
}
|
|
164
204
|
/** Batch preview response shape from the backend */
|
|
165
205
|
interface PreviewBatchResponse {
|
|
166
|
-
/** Key is orderId, value is preview or null if no conversation exists
|
|
206
|
+
/** Key is orderId, value is preview or null if no conversation exists.
|
|
207
|
+
* Scoped to a single `kind` per request — the backend filters server-side,
|
|
208
|
+
* so this map never mixes a case thread and a help thread for one order. */
|
|
167
209
|
previews: Record<string, ConversationPreview | null>;
|
|
168
210
|
}
|
|
169
211
|
/** Response from createConversationWithMessage (first-message flow) */
|
|
@@ -261,12 +303,19 @@ interface InviteUserPayload {
|
|
|
261
303
|
}
|
|
262
304
|
|
|
263
305
|
interface CollabPanelProps {
|
|
264
|
-
/** Order
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
306
|
+
/** Order this thread belongs to. Required for a `case` thread; omitted for a
|
|
307
|
+
* help channel, which belongs to a lab rather than an order. */
|
|
308
|
+
orderId?: string;
|
|
309
|
+
/** A thread the caller already resolved — how a help channel is opened.
|
|
310
|
+
* Skips the order-keyed preview lookup entirely. */
|
|
311
|
+
conversation?: Conversation | null;
|
|
312
|
+
/** Patient/study data displayed in the header. Absent on a help channel:
|
|
313
|
+
* there is no patient, and the header renders its support variant instead. */
|
|
314
|
+
patientData?: PatientData;
|
|
268
315
|
/** Participant user IDs — only used when creating a brand-new conversation */
|
|
269
316
|
participantIds?: string[];
|
|
317
|
+
/** Which thread on the case. Defaults to the shared `case` thread. */
|
|
318
|
+
kind?: ConversationKind;
|
|
270
319
|
/** Show "seen by" indicator under own messages (default true) */
|
|
271
320
|
showSeenBy?: boolean;
|
|
272
321
|
/**
|
|
@@ -317,7 +366,7 @@ interface CollabPanelProps {
|
|
|
317
366
|
* Full collaboration panel: patient header + pinned bar + message thread + input.
|
|
318
367
|
* Supports reply, pin/unpin, and (optionally) seen-by indicators.
|
|
319
368
|
*/
|
|
320
|
-
declare function CollabPanel({ orderId, patientData, participantIds, showSeenBy, onBack, hidePatientName, hideOpenCase, onConversationChange, themeMode, showSettings: controlledShowSettings, onSettingsChange, className, style, }: CollabPanelProps): react_jsx_runtime.JSX.Element;
|
|
369
|
+
declare function CollabPanel({ orderId, conversation: providedConversation, patientData, participantIds, kind, showSeenBy, onBack, hidePatientName, hideOpenCase, onConversationChange, themeMode, showSettings: controlledShowSettings, onSettingsChange, className, style, }: CollabPanelProps): react_jsx_runtime.JSX.Element;
|
|
321
370
|
|
|
322
371
|
interface CollabPopupProps {
|
|
323
372
|
/** Order ID for this conversation */
|
|
@@ -326,6 +375,8 @@ interface CollabPopupProps {
|
|
|
326
375
|
patientData: PatientData;
|
|
327
376
|
/** Participant user IDs — only used when creating a brand-new conversation */
|
|
328
377
|
participantIds?: string[];
|
|
378
|
+
/** Which thread on the case. Defaults to the shared `case` thread. */
|
|
379
|
+
kind?: ConversationKind;
|
|
329
380
|
/** Whether the popup is open */
|
|
330
381
|
isOpen: boolean;
|
|
331
382
|
/** Close the popup */
|
|
@@ -355,7 +406,7 @@ interface CollabPopupProps {
|
|
|
355
406
|
* Draggable floating chat popup — drop-in replacement for DraggableChatPopup.
|
|
356
407
|
* Renders a CollabPanel inside a movable, resizable container.
|
|
357
408
|
*/
|
|
358
|
-
declare function CollabPopup({ orderId, patientData, participantIds, isOpen, onClose, onBack, onMinimize, initialPosition, width, height, className, }: CollabPopupProps): react_jsx_runtime.JSX.Element | null;
|
|
409
|
+
declare function CollabPopup({ orderId, patientData, participantIds, kind, isOpen, onClose, onBack, onMinimize, initialPosition, width, height, className, }: CollabPopupProps): react_jsx_runtime.JSX.Element | null;
|
|
359
410
|
|
|
360
411
|
type ColabInlineMode = 'light' | 'dark';
|
|
361
412
|
interface CollabInlineProps {
|
|
@@ -363,6 +414,8 @@ interface CollabInlineProps {
|
|
|
363
414
|
patientData: PatientData;
|
|
364
415
|
/** User IDs to invite when the first message creates the conversation */
|
|
365
416
|
participantIds?: string[];
|
|
417
|
+
/** Which thread on the case. Defaults to the shared `case` thread. */
|
|
418
|
+
kind?: ConversationKind;
|
|
366
419
|
/** Called when user clicks the expand button — host opens the floating popup */
|
|
367
420
|
onExpand?: () => void;
|
|
368
421
|
/** Max inline messages to show (default 1 — just the latest) */
|
|
@@ -390,7 +443,7 @@ interface CollabInlineProps {
|
|
|
390
443
|
* Supports text and voice messages. File attachments and full chat features
|
|
391
444
|
* stay in the floating popup / inbox.
|
|
392
445
|
*/
|
|
393
|
-
declare function CollabInline({ orderId, patientData, participantIds, onExpand, messageLimit, placeholder, mode, className, style, }: CollabInlineProps): react_jsx_runtime.JSX.Element;
|
|
446
|
+
declare function CollabInline({ orderId, patientData, participantIds, kind, onExpand, messageLimit, placeholder, mode, className, style, }: CollabInlineProps): react_jsx_runtime.JSX.Element;
|
|
394
447
|
|
|
395
448
|
interface CollabInboxProps {
|
|
396
449
|
/** Optional: preselect a specific conversation (by conversation ID) */
|
|
@@ -552,6 +605,8 @@ interface FetchMessagesOptions {
|
|
|
552
605
|
interface CreateConversationOptions {
|
|
553
606
|
name: string;
|
|
554
607
|
participantIds?: string[];
|
|
608
|
+
/** Which thread to create. Defaults to the shared case thread. */
|
|
609
|
+
kind?: ConversationKind;
|
|
555
610
|
}
|
|
556
611
|
interface CollabContextValue {
|
|
557
612
|
socket: CollabSocket;
|
|
@@ -573,9 +628,9 @@ interface CollabContextValue {
|
|
|
573
628
|
*/
|
|
574
629
|
unreadCountsByOrder: Record<string, number>;
|
|
575
630
|
/** Batched preview lookup — coalesces calls within a microtask */
|
|
576
|
-
requestPreview: (orderId: string) => Promise<ConversationPreview | null>;
|
|
631
|
+
requestPreview: (orderId: string, kind?: ConversationKind) => Promise<ConversationPreview | null>;
|
|
577
632
|
/** Invalidate a cached preview (e.g. when a new message arrives) */
|
|
578
|
-
invalidatePreview: (orderId: string) => void;
|
|
633
|
+
invalidatePreview: (orderId: string, kind?: ConversationKind) => void;
|
|
579
634
|
/** Fetch paginated message history */
|
|
580
635
|
fetchMessages: (conversationId: string, options?: FetchMessagesOptions) => Promise<Message[]>;
|
|
581
636
|
/** Atomic create-or-send — creates conversation if missing, then stores the first message */
|
|
@@ -603,12 +658,38 @@ interface CollabProviderProps {
|
|
|
603
658
|
declare function CollabProvider({ config, apiBaseUrl, children }: CollabProviderProps): react_jsx_runtime.JSX.Element | null;
|
|
604
659
|
|
|
605
660
|
interface UseConversationOptions {
|
|
606
|
-
|
|
607
|
-
|
|
661
|
+
/**
|
|
662
|
+
* The order this thread belongs to. Required for a `case` thread, which is
|
|
663
|
+
* created lazily on first message and resolved by an order-keyed preview.
|
|
664
|
+
* Omitted for a help channel — that belongs to a lab, not an order.
|
|
665
|
+
*/
|
|
666
|
+
orderId?: string;
|
|
667
|
+
/**
|
|
668
|
+
* A thread the caller has ALREADY resolved, opened directly instead of being
|
|
669
|
+
* looked up by order.
|
|
670
|
+
*
|
|
671
|
+
* This is how a help channel opens. The backend's `GET /help_channel` does
|
|
672
|
+
* the get-or-create and hands back the conversation, so there is nothing to
|
|
673
|
+
* look up and nothing to lazily create — passing it here skips the preview
|
|
674
|
+
* request entirely. The preview endpoint is order-keyed and could not serve
|
|
675
|
+
* an order-less thread in any case.
|
|
676
|
+
*/
|
|
677
|
+
conversation?: Conversation | null;
|
|
678
|
+
/** Patient/study context. Absent on a help channel — there is no patient. */
|
|
679
|
+
patientData?: PatientData;
|
|
608
680
|
/** Participant user IDs used only when creating a brand-new conversation */
|
|
609
681
|
participantIds?: string[];
|
|
610
682
|
/** Load full history on mount (default true) */
|
|
611
683
|
loadHistory?: boolean;
|
|
684
|
+
/**
|
|
685
|
+
* What this thread is. Defaults to the shared `case` thread, so every
|
|
686
|
+
* existing caller is unaffected.
|
|
687
|
+
*
|
|
688
|
+
* For `help_lab` the backend seats only the imaging centre plus Natoe
|
|
689
|
+
* support, and `participantIds` is ignored server-side — a help channel must
|
|
690
|
+
* never be widened by the client.
|
|
691
|
+
*/
|
|
692
|
+
kind?: ConversationKind;
|
|
612
693
|
}
|
|
613
694
|
interface UseConversationReturn {
|
|
614
695
|
conversation: Conversation | null;
|
|
@@ -643,7 +724,7 @@ interface UseConversationReturn {
|
|
|
643
724
|
* when the user sends the first message. If a conversation already exists for
|
|
644
725
|
* the given orderId, it's loaded and joined automatically.
|
|
645
726
|
*/
|
|
646
|
-
declare function useConversation({ orderId, patientData, participantIds, loadHistory, }: UseConversationOptions): UseConversationReturn;
|
|
727
|
+
declare function useConversation({ orderId, conversation: providedConversation, patientData, participantIds, loadHistory, kind, }: UseConversationOptions): UseConversationReturn;
|
|
647
728
|
|
|
648
729
|
interface UseConversationListOptions {
|
|
649
730
|
/**
|
|
@@ -677,6 +758,8 @@ interface UseInlineCollabOptions {
|
|
|
677
758
|
patientData: PatientData;
|
|
678
759
|
/** Participant IDs passed to the backend only when creating a new conversation */
|
|
679
760
|
participantIds?: string[];
|
|
761
|
+
/** Which thread on the case. Defaults to the shared `case` thread. */
|
|
762
|
+
kind?: ConversationKind;
|
|
680
763
|
/** Max messages to keep in inline state (default 5) */
|
|
681
764
|
messageLimit?: number;
|
|
682
765
|
}
|
|
@@ -704,7 +787,7 @@ interface UseInlineCollabReturn {
|
|
|
704
787
|
* - First sendMessage creates conversation atomically + starts real-time flow
|
|
705
788
|
* - Subsequent sends go through the socket
|
|
706
789
|
*/
|
|
707
|
-
declare function useInlineCollab({ orderId, patientData, participantIds, messageLimit, }: UseInlineCollabOptions): UseInlineCollabReturn;
|
|
790
|
+
declare function useInlineCollab({ orderId, patientData, participantIds, messageLimit, kind, }: UseInlineCollabOptions): UseInlineCollabReturn;
|
|
708
791
|
|
|
709
792
|
interface UseMessagesOptions {
|
|
710
793
|
conversationId: string | null;
|
|
@@ -907,6 +990,13 @@ interface PatientHeaderProps {
|
|
|
907
990
|
hideName?: boolean;
|
|
908
991
|
/** Override the displayed name — use the stored conversation.name to avoid reconstructing from patientData components */
|
|
909
992
|
displayName?: string;
|
|
993
|
+
/**
|
|
994
|
+
* Render the support variant: a help channel has no patient, no study and no
|
|
995
|
+
* case, so the demographics line and every case-level action are suppressed
|
|
996
|
+
* and the title is the channel name. Without this the header would show a
|
|
997
|
+
* row of empty fields and a dead "View DICOM" button.
|
|
998
|
+
*/
|
|
999
|
+
isSupportChannel?: boolean;
|
|
910
1000
|
className?: string;
|
|
911
1001
|
}
|
|
912
1002
|
/**
|
|
@@ -924,7 +1014,7 @@ interface PatientHeaderProps {
|
|
|
924
1014
|
* When `hideName=true` (CollabPopup wraps the conversation in its own
|
|
925
1015
|
* window title), only the meta + actions row renders.
|
|
926
1016
|
*/
|
|
927
|
-
declare function PatientHeader({ patientData, participants, onOpenDicom, onOpenCase, onOpenSettings, onBack, hideName, displayName, className, }: PatientHeaderProps): react_jsx_runtime.JSX.Element;
|
|
1017
|
+
declare function PatientHeader({ patientData, participants, onOpenDicom, onOpenCase, onOpenSettings, onBack, hideName, displayName, isSupportChannel, className, }: PatientHeaderProps): react_jsx_runtime.JSX.Element;
|
|
928
1018
|
|
|
929
1019
|
interface MessageListHandle {
|
|
930
1020
|
/** Scroll to a specific message by ID (used by pin jump-to) */
|
|
@@ -1187,4 +1277,4 @@ declare const SUPPORTED_IMAGE_TYPES: string[];
|
|
|
1187
1277
|
/** Max file size in bytes (20MB) */
|
|
1188
1278
|
declare const MAX_FILE_SIZE: number;
|
|
1189
1279
|
|
|
1190
|
-
export { AUDIO_MIME_TYPE, type ChannelEvent, ChannelSettings, type ChannelUpdatePayload, type CollabConfig, type CollabError, CollabInbox, CollabInline, CollabPanel, CollabPopup, CollabProvider, CollabSocket, type Conversation, ConversationList, ConversationListItem, type ConversationListItem$1 as ConversationListItemData, type ConversationPreview, type CreateConversationResponse, DEEP_LINK_PREFIX, EVENTS, type InviteUserPayload, MAX_FILE_SIZE, MAX_PINNED_MESSAGES, MESSAGES_PAGE_SIZE, MESSAGE_TYPES, type Message, MessageActionsMenu, MessageBubble, MessageInput, MessageList, type MessageListHandle, type MessageSnapshot, type MessageType, type Participant, ParticipantsList, type PatientData, PatientHeader, PinnedMessagesBar, type PreviewBatchResponse, ReplyPreview, ReplyQuoteBlock, SUPPORTED_IMAGE_TYPES, SeenByIndicator, type SendMessagePayload, THEME_DEFAULTS, THEME_VAR, TYPING_DEBOUNCE_MS, type Theme, type TypingEvent, type UserRole, applyThemeOverrides, useAudioRecorder, useChannelSettings, useCollab, useConversation, useConversationList, useDeepLinks, useInlineCollab, useMessages, usePinnedMessages, useUnreadCount };
|
|
1280
|
+
export { AUDIO_MIME_TYPE, type ChannelEvent, ChannelSettings, type ChannelUpdatePayload, type CollabConfig, type CollabError, CollabInbox, CollabInline, CollabPanel, CollabPopup, CollabProvider, CollabSocket, type Conversation, type ConversationKind, ConversationList, ConversationListItem, type ConversationListItem$1 as ConversationListItemData, type ConversationPreview, type CreateConversationResponse, DEEP_LINK_PREFIX, EVENTS, type InviteUserPayload, MAX_FILE_SIZE, MAX_PINNED_MESSAGES, MESSAGES_PAGE_SIZE, MESSAGE_TYPES, type Message, MessageActionsMenu, MessageBubble, MessageInput, MessageList, type MessageListHandle, type MessageSnapshot, type MessageType, type Participant, ParticipantsList, type PatientData, PatientHeader, PinnedMessagesBar, type PreviewBatchResponse, ReplyPreview, ReplyQuoteBlock, SUPPORTED_IMAGE_TYPES, SeenByIndicator, type SendMessagePayload, THEME_DEFAULTS, THEME_VAR, TYPING_DEBOUNCE_MS, type Theme, type TypingEvent, type UserRole, applyThemeOverrides, isCaseKind, isHelpKind, useAudioRecorder, useChannelSettings, useCollab, useConversation, useConversationList, useDeepLinks, useInlineCollab, useMessages, usePinnedMessages, useUnreadCount };
|
package/dist/index.d.ts
CHANGED
|
@@ -118,17 +118,51 @@ interface PatientData {
|
|
|
118
118
|
labName?: string;
|
|
119
119
|
bodyParts?: string[];
|
|
120
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* What a thread is about — and, crucially, what it is SCOPED to.
|
|
123
|
+
*
|
|
124
|
+
* - `case` — the discussion about one clinical order. Scoped to an order,
|
|
125
|
+
* so `orderId` is always set. Lab, radiologist, physician, admin.
|
|
126
|
+
* - `help_lab` — an imaging centre's help channel with Natoe support. Scoped to
|
|
127
|
+
* the LAB, not to any case: it has NO `orderId`, it outlives
|
|
128
|
+
* every order, and there is exactly one per imaging centre.
|
|
129
|
+
*
|
|
130
|
+
* `help_lab` was briefly modelled as per-case (one help thread per order). It is
|
|
131
|
+
* now per-lab, so support gets one continuous thread with each imaging centre
|
|
132
|
+
* rather than N short-lived ones scattered across cases. A case can still be
|
|
133
|
+
* referenced from inside the channel; it just no longer scopes it.
|
|
134
|
+
*
|
|
135
|
+
* Isolation — who can see a help channel — is enforced by the backend's
|
|
136
|
+
* participant seeding, never by anything in this package. Treat this as a label
|
|
137
|
+
* for rendering and for addressing the right thread, not as a security boundary.
|
|
138
|
+
*
|
|
139
|
+
* Optional everywhere, defaulting to `case`, so callers written before help
|
|
140
|
+
* channels existed keep their exact previous behaviour.
|
|
141
|
+
*/
|
|
142
|
+
type ConversationKind = 'case' | 'help_lab';
|
|
143
|
+
declare function isHelpKind(kind?: ConversationKind | string): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* True when a thread is scoped to an order and therefore has patient context to
|
|
146
|
+
* render. Prefer this over testing `orderId` directly: a help channel has no
|
|
147
|
+
* order, so every patient-shaped affordance must be skipped for it.
|
|
148
|
+
*/
|
|
149
|
+
declare function isCaseKind(kind?: ConversationKind | string): boolean;
|
|
121
150
|
interface Conversation {
|
|
122
151
|
id: string;
|
|
123
|
-
|
|
152
|
+
/** Absent on a help channel — that thread belongs to a lab, not an order. */
|
|
153
|
+
orderId?: string;
|
|
154
|
+
/** Set only on a help channel: the imaging centre that owns it. */
|
|
155
|
+
labUserId?: string;
|
|
124
156
|
name: string;
|
|
157
|
+
kind?: ConversationKind;
|
|
125
158
|
picture?: string;
|
|
126
159
|
participants: Participant[];
|
|
127
160
|
lastMessage?: Message;
|
|
128
161
|
unreadCount: number;
|
|
129
162
|
createdAt: string;
|
|
130
163
|
updatedAt: string;
|
|
131
|
-
/** Denormalized patient data snapshot — lets UI render without extra fetch
|
|
164
|
+
/** Denormalized patient data snapshot — lets UI render without extra fetch.
|
|
165
|
+
* Always absent on a help channel: there is no patient. */
|
|
132
166
|
patientSnapshot?: PatientData;
|
|
133
167
|
/** Currently pinned messages (max 3) */
|
|
134
168
|
pinnedMessages?: Message[];
|
|
@@ -139,8 +173,13 @@ interface Conversation {
|
|
|
139
173
|
*/
|
|
140
174
|
interface ConversationListItem$1 {
|
|
141
175
|
id: string;
|
|
142
|
-
orderId
|
|
176
|
+
/** Absent on a help channel — see `Conversation.orderId`. */
|
|
177
|
+
orderId?: string;
|
|
178
|
+
labUserId?: string;
|
|
143
179
|
name: string;
|
|
180
|
+
/** Lets the inbox render the lab's help channel distinctly from its case
|
|
181
|
+
* threads — they appear as separate rows. */
|
|
182
|
+
kind?: ConversationKind;
|
|
144
183
|
picture?: string;
|
|
145
184
|
unreadCount: number;
|
|
146
185
|
lastMessage?: Message;
|
|
@@ -154,6 +193,7 @@ interface ConversationListItem$1 {
|
|
|
154
193
|
interface ConversationPreview {
|
|
155
194
|
conversationId: string;
|
|
156
195
|
orderId: string;
|
|
196
|
+
kind?: ConversationKind;
|
|
157
197
|
messageCount: number;
|
|
158
198
|
unreadCount: number;
|
|
159
199
|
/** Last N messages (typically 5) for inline display */
|
|
@@ -163,7 +203,9 @@ interface ConversationPreview {
|
|
|
163
203
|
}
|
|
164
204
|
/** Batch preview response shape from the backend */
|
|
165
205
|
interface PreviewBatchResponse {
|
|
166
|
-
/** Key is orderId, value is preview or null if no conversation exists
|
|
206
|
+
/** Key is orderId, value is preview or null if no conversation exists.
|
|
207
|
+
* Scoped to a single `kind` per request — the backend filters server-side,
|
|
208
|
+
* so this map never mixes a case thread and a help thread for one order. */
|
|
167
209
|
previews: Record<string, ConversationPreview | null>;
|
|
168
210
|
}
|
|
169
211
|
/** Response from createConversationWithMessage (first-message flow) */
|
|
@@ -261,12 +303,19 @@ interface InviteUserPayload {
|
|
|
261
303
|
}
|
|
262
304
|
|
|
263
305
|
interface CollabPanelProps {
|
|
264
|
-
/** Order
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
306
|
+
/** Order this thread belongs to. Required for a `case` thread; omitted for a
|
|
307
|
+
* help channel, which belongs to a lab rather than an order. */
|
|
308
|
+
orderId?: string;
|
|
309
|
+
/** A thread the caller already resolved — how a help channel is opened.
|
|
310
|
+
* Skips the order-keyed preview lookup entirely. */
|
|
311
|
+
conversation?: Conversation | null;
|
|
312
|
+
/** Patient/study data displayed in the header. Absent on a help channel:
|
|
313
|
+
* there is no patient, and the header renders its support variant instead. */
|
|
314
|
+
patientData?: PatientData;
|
|
268
315
|
/** Participant user IDs — only used when creating a brand-new conversation */
|
|
269
316
|
participantIds?: string[];
|
|
317
|
+
/** Which thread on the case. Defaults to the shared `case` thread. */
|
|
318
|
+
kind?: ConversationKind;
|
|
270
319
|
/** Show "seen by" indicator under own messages (default true) */
|
|
271
320
|
showSeenBy?: boolean;
|
|
272
321
|
/**
|
|
@@ -317,7 +366,7 @@ interface CollabPanelProps {
|
|
|
317
366
|
* Full collaboration panel: patient header + pinned bar + message thread + input.
|
|
318
367
|
* Supports reply, pin/unpin, and (optionally) seen-by indicators.
|
|
319
368
|
*/
|
|
320
|
-
declare function CollabPanel({ orderId, patientData, participantIds, showSeenBy, onBack, hidePatientName, hideOpenCase, onConversationChange, themeMode, showSettings: controlledShowSettings, onSettingsChange, className, style, }: CollabPanelProps): react_jsx_runtime.JSX.Element;
|
|
369
|
+
declare function CollabPanel({ orderId, conversation: providedConversation, patientData, participantIds, kind, showSeenBy, onBack, hidePatientName, hideOpenCase, onConversationChange, themeMode, showSettings: controlledShowSettings, onSettingsChange, className, style, }: CollabPanelProps): react_jsx_runtime.JSX.Element;
|
|
321
370
|
|
|
322
371
|
interface CollabPopupProps {
|
|
323
372
|
/** Order ID for this conversation */
|
|
@@ -326,6 +375,8 @@ interface CollabPopupProps {
|
|
|
326
375
|
patientData: PatientData;
|
|
327
376
|
/** Participant user IDs — only used when creating a brand-new conversation */
|
|
328
377
|
participantIds?: string[];
|
|
378
|
+
/** Which thread on the case. Defaults to the shared `case` thread. */
|
|
379
|
+
kind?: ConversationKind;
|
|
329
380
|
/** Whether the popup is open */
|
|
330
381
|
isOpen: boolean;
|
|
331
382
|
/** Close the popup */
|
|
@@ -355,7 +406,7 @@ interface CollabPopupProps {
|
|
|
355
406
|
* Draggable floating chat popup — drop-in replacement for DraggableChatPopup.
|
|
356
407
|
* Renders a CollabPanel inside a movable, resizable container.
|
|
357
408
|
*/
|
|
358
|
-
declare function CollabPopup({ orderId, patientData, participantIds, isOpen, onClose, onBack, onMinimize, initialPosition, width, height, className, }: CollabPopupProps): react_jsx_runtime.JSX.Element | null;
|
|
409
|
+
declare function CollabPopup({ orderId, patientData, participantIds, kind, isOpen, onClose, onBack, onMinimize, initialPosition, width, height, className, }: CollabPopupProps): react_jsx_runtime.JSX.Element | null;
|
|
359
410
|
|
|
360
411
|
type ColabInlineMode = 'light' | 'dark';
|
|
361
412
|
interface CollabInlineProps {
|
|
@@ -363,6 +414,8 @@ interface CollabInlineProps {
|
|
|
363
414
|
patientData: PatientData;
|
|
364
415
|
/** User IDs to invite when the first message creates the conversation */
|
|
365
416
|
participantIds?: string[];
|
|
417
|
+
/** Which thread on the case. Defaults to the shared `case` thread. */
|
|
418
|
+
kind?: ConversationKind;
|
|
366
419
|
/** Called when user clicks the expand button — host opens the floating popup */
|
|
367
420
|
onExpand?: () => void;
|
|
368
421
|
/** Max inline messages to show (default 1 — just the latest) */
|
|
@@ -390,7 +443,7 @@ interface CollabInlineProps {
|
|
|
390
443
|
* Supports text and voice messages. File attachments and full chat features
|
|
391
444
|
* stay in the floating popup / inbox.
|
|
392
445
|
*/
|
|
393
|
-
declare function CollabInline({ orderId, patientData, participantIds, onExpand, messageLimit, placeholder, mode, className, style, }: CollabInlineProps): react_jsx_runtime.JSX.Element;
|
|
446
|
+
declare function CollabInline({ orderId, patientData, participantIds, kind, onExpand, messageLimit, placeholder, mode, className, style, }: CollabInlineProps): react_jsx_runtime.JSX.Element;
|
|
394
447
|
|
|
395
448
|
interface CollabInboxProps {
|
|
396
449
|
/** Optional: preselect a specific conversation (by conversation ID) */
|
|
@@ -552,6 +605,8 @@ interface FetchMessagesOptions {
|
|
|
552
605
|
interface CreateConversationOptions {
|
|
553
606
|
name: string;
|
|
554
607
|
participantIds?: string[];
|
|
608
|
+
/** Which thread to create. Defaults to the shared case thread. */
|
|
609
|
+
kind?: ConversationKind;
|
|
555
610
|
}
|
|
556
611
|
interface CollabContextValue {
|
|
557
612
|
socket: CollabSocket;
|
|
@@ -573,9 +628,9 @@ interface CollabContextValue {
|
|
|
573
628
|
*/
|
|
574
629
|
unreadCountsByOrder: Record<string, number>;
|
|
575
630
|
/** Batched preview lookup — coalesces calls within a microtask */
|
|
576
|
-
requestPreview: (orderId: string) => Promise<ConversationPreview | null>;
|
|
631
|
+
requestPreview: (orderId: string, kind?: ConversationKind) => Promise<ConversationPreview | null>;
|
|
577
632
|
/** Invalidate a cached preview (e.g. when a new message arrives) */
|
|
578
|
-
invalidatePreview: (orderId: string) => void;
|
|
633
|
+
invalidatePreview: (orderId: string, kind?: ConversationKind) => void;
|
|
579
634
|
/** Fetch paginated message history */
|
|
580
635
|
fetchMessages: (conversationId: string, options?: FetchMessagesOptions) => Promise<Message[]>;
|
|
581
636
|
/** Atomic create-or-send — creates conversation if missing, then stores the first message */
|
|
@@ -603,12 +658,38 @@ interface CollabProviderProps {
|
|
|
603
658
|
declare function CollabProvider({ config, apiBaseUrl, children }: CollabProviderProps): react_jsx_runtime.JSX.Element | null;
|
|
604
659
|
|
|
605
660
|
interface UseConversationOptions {
|
|
606
|
-
|
|
607
|
-
|
|
661
|
+
/**
|
|
662
|
+
* The order this thread belongs to. Required for a `case` thread, which is
|
|
663
|
+
* created lazily on first message and resolved by an order-keyed preview.
|
|
664
|
+
* Omitted for a help channel — that belongs to a lab, not an order.
|
|
665
|
+
*/
|
|
666
|
+
orderId?: string;
|
|
667
|
+
/**
|
|
668
|
+
* A thread the caller has ALREADY resolved, opened directly instead of being
|
|
669
|
+
* looked up by order.
|
|
670
|
+
*
|
|
671
|
+
* This is how a help channel opens. The backend's `GET /help_channel` does
|
|
672
|
+
* the get-or-create and hands back the conversation, so there is nothing to
|
|
673
|
+
* look up and nothing to lazily create — passing it here skips the preview
|
|
674
|
+
* request entirely. The preview endpoint is order-keyed and could not serve
|
|
675
|
+
* an order-less thread in any case.
|
|
676
|
+
*/
|
|
677
|
+
conversation?: Conversation | null;
|
|
678
|
+
/** Patient/study context. Absent on a help channel — there is no patient. */
|
|
679
|
+
patientData?: PatientData;
|
|
608
680
|
/** Participant user IDs used only when creating a brand-new conversation */
|
|
609
681
|
participantIds?: string[];
|
|
610
682
|
/** Load full history on mount (default true) */
|
|
611
683
|
loadHistory?: boolean;
|
|
684
|
+
/**
|
|
685
|
+
* What this thread is. Defaults to the shared `case` thread, so every
|
|
686
|
+
* existing caller is unaffected.
|
|
687
|
+
*
|
|
688
|
+
* For `help_lab` the backend seats only the imaging centre plus Natoe
|
|
689
|
+
* support, and `participantIds` is ignored server-side — a help channel must
|
|
690
|
+
* never be widened by the client.
|
|
691
|
+
*/
|
|
692
|
+
kind?: ConversationKind;
|
|
612
693
|
}
|
|
613
694
|
interface UseConversationReturn {
|
|
614
695
|
conversation: Conversation | null;
|
|
@@ -643,7 +724,7 @@ interface UseConversationReturn {
|
|
|
643
724
|
* when the user sends the first message. If a conversation already exists for
|
|
644
725
|
* the given orderId, it's loaded and joined automatically.
|
|
645
726
|
*/
|
|
646
|
-
declare function useConversation({ orderId, patientData, participantIds, loadHistory, }: UseConversationOptions): UseConversationReturn;
|
|
727
|
+
declare function useConversation({ orderId, conversation: providedConversation, patientData, participantIds, loadHistory, kind, }: UseConversationOptions): UseConversationReturn;
|
|
647
728
|
|
|
648
729
|
interface UseConversationListOptions {
|
|
649
730
|
/**
|
|
@@ -677,6 +758,8 @@ interface UseInlineCollabOptions {
|
|
|
677
758
|
patientData: PatientData;
|
|
678
759
|
/** Participant IDs passed to the backend only when creating a new conversation */
|
|
679
760
|
participantIds?: string[];
|
|
761
|
+
/** Which thread on the case. Defaults to the shared `case` thread. */
|
|
762
|
+
kind?: ConversationKind;
|
|
680
763
|
/** Max messages to keep in inline state (default 5) */
|
|
681
764
|
messageLimit?: number;
|
|
682
765
|
}
|
|
@@ -704,7 +787,7 @@ interface UseInlineCollabReturn {
|
|
|
704
787
|
* - First sendMessage creates conversation atomically + starts real-time flow
|
|
705
788
|
* - Subsequent sends go through the socket
|
|
706
789
|
*/
|
|
707
|
-
declare function useInlineCollab({ orderId, patientData, participantIds, messageLimit, }: UseInlineCollabOptions): UseInlineCollabReturn;
|
|
790
|
+
declare function useInlineCollab({ orderId, patientData, participantIds, messageLimit, kind, }: UseInlineCollabOptions): UseInlineCollabReturn;
|
|
708
791
|
|
|
709
792
|
interface UseMessagesOptions {
|
|
710
793
|
conversationId: string | null;
|
|
@@ -907,6 +990,13 @@ interface PatientHeaderProps {
|
|
|
907
990
|
hideName?: boolean;
|
|
908
991
|
/** Override the displayed name — use the stored conversation.name to avoid reconstructing from patientData components */
|
|
909
992
|
displayName?: string;
|
|
993
|
+
/**
|
|
994
|
+
* Render the support variant: a help channel has no patient, no study and no
|
|
995
|
+
* case, so the demographics line and every case-level action are suppressed
|
|
996
|
+
* and the title is the channel name. Without this the header would show a
|
|
997
|
+
* row of empty fields and a dead "View DICOM" button.
|
|
998
|
+
*/
|
|
999
|
+
isSupportChannel?: boolean;
|
|
910
1000
|
className?: string;
|
|
911
1001
|
}
|
|
912
1002
|
/**
|
|
@@ -924,7 +1014,7 @@ interface PatientHeaderProps {
|
|
|
924
1014
|
* When `hideName=true` (CollabPopup wraps the conversation in its own
|
|
925
1015
|
* window title), only the meta + actions row renders.
|
|
926
1016
|
*/
|
|
927
|
-
declare function PatientHeader({ patientData, participants, onOpenDicom, onOpenCase, onOpenSettings, onBack, hideName, displayName, className, }: PatientHeaderProps): react_jsx_runtime.JSX.Element;
|
|
1017
|
+
declare function PatientHeader({ patientData, participants, onOpenDicom, onOpenCase, onOpenSettings, onBack, hideName, displayName, isSupportChannel, className, }: PatientHeaderProps): react_jsx_runtime.JSX.Element;
|
|
928
1018
|
|
|
929
1019
|
interface MessageListHandle {
|
|
930
1020
|
/** Scroll to a specific message by ID (used by pin jump-to) */
|
|
@@ -1187,4 +1277,4 @@ declare const SUPPORTED_IMAGE_TYPES: string[];
|
|
|
1187
1277
|
/** Max file size in bytes (20MB) */
|
|
1188
1278
|
declare const MAX_FILE_SIZE: number;
|
|
1189
1279
|
|
|
1190
|
-
export { AUDIO_MIME_TYPE, type ChannelEvent, ChannelSettings, type ChannelUpdatePayload, type CollabConfig, type CollabError, CollabInbox, CollabInline, CollabPanel, CollabPopup, CollabProvider, CollabSocket, type Conversation, ConversationList, ConversationListItem, type ConversationListItem$1 as ConversationListItemData, type ConversationPreview, type CreateConversationResponse, DEEP_LINK_PREFIX, EVENTS, type InviteUserPayload, MAX_FILE_SIZE, MAX_PINNED_MESSAGES, MESSAGES_PAGE_SIZE, MESSAGE_TYPES, type Message, MessageActionsMenu, MessageBubble, MessageInput, MessageList, type MessageListHandle, type MessageSnapshot, type MessageType, type Participant, ParticipantsList, type PatientData, PatientHeader, PinnedMessagesBar, type PreviewBatchResponse, ReplyPreview, ReplyQuoteBlock, SUPPORTED_IMAGE_TYPES, SeenByIndicator, type SendMessagePayload, THEME_DEFAULTS, THEME_VAR, TYPING_DEBOUNCE_MS, type Theme, type TypingEvent, type UserRole, applyThemeOverrides, useAudioRecorder, useChannelSettings, useCollab, useConversation, useConversationList, useDeepLinks, useInlineCollab, useMessages, usePinnedMessages, useUnreadCount };
|
|
1280
|
+
export { AUDIO_MIME_TYPE, type ChannelEvent, ChannelSettings, type ChannelUpdatePayload, type CollabConfig, type CollabError, CollabInbox, CollabInline, CollabPanel, CollabPopup, CollabProvider, CollabSocket, type Conversation, type ConversationKind, ConversationList, ConversationListItem, type ConversationListItem$1 as ConversationListItemData, type ConversationPreview, type CreateConversationResponse, DEEP_LINK_PREFIX, EVENTS, type InviteUserPayload, MAX_FILE_SIZE, MAX_PINNED_MESSAGES, MESSAGES_PAGE_SIZE, MESSAGE_TYPES, type Message, MessageActionsMenu, MessageBubble, MessageInput, MessageList, type MessageListHandle, type MessageSnapshot, type MessageType, type Participant, ParticipantsList, type PatientData, PatientHeader, PinnedMessagesBar, type PreviewBatchResponse, ReplyPreview, ReplyQuoteBlock, SUPPORTED_IMAGE_TYPES, SeenByIndicator, type SendMessagePayload, THEME_DEFAULTS, THEME_VAR, TYPING_DEBOUNCE_MS, type Theme, type TypingEvent, type UserRole, applyThemeOverrides, isCaseKind, isHelpKind, useAudioRecorder, useChannelSettings, useCollab, useConversation, useConversationList, useDeepLinks, useInlineCollab, useMessages, usePinnedMessages, useUnreadCount };
|