@natoe/colab 0.1.0
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/README.md +171 -0
- package/dist/index.d.mts +865 -0
- package/dist/index.d.ts +865 -0
- package/dist/index.js +4932 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4893 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# @natoe/colab
|
|
2
|
+
|
|
3
|
+
Real-time, study-aware collaboration UI for radiology workflows. Drop-in chat
|
|
4
|
+
components and React hooks built on Phoenix Channels — designed to plug into a
|
|
5
|
+
host app that already manages auth, file uploads, and DICOM viewing.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @natoe/colab
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @natoe/colab
|
|
13
|
+
# or
|
|
14
|
+
yarn add @natoe/colab
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Peer dependencies: `react >= 18`, `react-dom >= 18`.
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
Wrap your app in `CollabProvider`, then drop `<CollabPopup>` (or one of the
|
|
22
|
+
other surfaces) wherever you want chat to appear.
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { CollabProvider, CollabPopup } from '@natoe/colab';
|
|
26
|
+
|
|
27
|
+
function App() {
|
|
28
|
+
const config = {
|
|
29
|
+
socketUrl: 'wss://your-backend/socket',
|
|
30
|
+
getToken: () => localStorage.getItem('jwt') ?? '',
|
|
31
|
+
userId: currentUser.id,
|
|
32
|
+
userRole: 'radiologist', // 'lab' | 'radiologist' | 'physician' | 'admin'
|
|
33
|
+
userName: currentUser.name,
|
|
34
|
+
|
|
35
|
+
// Host-app callbacks — colab calls these, never implements them.
|
|
36
|
+
onOpenDicom: (studyId, storageId) => openViewer(studyId, storageId),
|
|
37
|
+
onUploadFile: async (file, fileName) => {
|
|
38
|
+
const url = await uploadToS3(file, fileName);
|
|
39
|
+
return url;
|
|
40
|
+
},
|
|
41
|
+
onDeepLink: (path) => router.push(path),
|
|
42
|
+
onError: (err) => reportToSentry(err),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<CollabProvider config={config} apiBaseUrl="https://your-backend">
|
|
47
|
+
{/* ...your app... */}
|
|
48
|
+
|
|
49
|
+
<CollabPopup
|
|
50
|
+
orderId={order.id}
|
|
51
|
+
patientData={{
|
|
52
|
+
orderId: order.id,
|
|
53
|
+
patientName: 'Jane Doe',
|
|
54
|
+
patientAge: '54',
|
|
55
|
+
patientSex: 'F',
|
|
56
|
+
studyType: 'CT Chest',
|
|
57
|
+
studyId: order.dicomStudyId, // PACS UID — gates the "View DICOM" button
|
|
58
|
+
storageId: 'PACS', // required alongside studyId
|
|
59
|
+
}}
|
|
60
|
+
participantIds={[labUserId, radiologistId, adminId]}
|
|
61
|
+
isOpen={chatOpen}
|
|
62
|
+
onClose={() => setChatOpen(false)}
|
|
63
|
+
/>
|
|
64
|
+
</CollabProvider>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## What's in the box
|
|
70
|
+
|
|
71
|
+
### Surfaces (pick one or compose)
|
|
72
|
+
|
|
73
|
+
| Component | Use when… |
|
|
74
|
+
| --------------- | ------------------------------------------------------------------------ |
|
|
75
|
+
| `CollabPopup` | Floating, draggable chat window — typical for table-row "Open chat". |
|
|
76
|
+
| `CollabPanel` | Full-bleed panel, e.g. side-docked next to a viewer. |
|
|
77
|
+
| `CollabInline` | Last-N-messages preview embedded directly in a table row. |
|
|
78
|
+
| `CollabInbox` | WhatsApp-style two-pane inbox: conversation list + active conversation. |
|
|
79
|
+
|
|
80
|
+
### Provider
|
|
81
|
+
|
|
82
|
+
`CollabProvider` owns the socket connection, identity, and host callbacks.
|
|
83
|
+
Wrap your app once near the root.
|
|
84
|
+
|
|
85
|
+
### Hooks (for custom UI)
|
|
86
|
+
|
|
87
|
+
- `useCollab` — read config, socket, error stream
|
|
88
|
+
- `useConversation` — single conversation: messages, typing, send/edit/delete
|
|
89
|
+
- `useConversationList` — inbox list with unread counts and last activity
|
|
90
|
+
- `useMessages` — paginated message history with realtime appends
|
|
91
|
+
- `useInlineCollab` — batch preview fetcher for table rows
|
|
92
|
+
- `useUnreadCount` — total unread badge for nav bars
|
|
93
|
+
- `useChannelSettings`, `usePinnedMessages`, `useDeepLinks`, `useAudioRecorder`
|
|
94
|
+
|
|
95
|
+
### Composable parts
|
|
96
|
+
|
|
97
|
+
If the prebuilt surfaces don't fit, compose your own from
|
|
98
|
+
`ConversationList`, `MessageList`, `MessageBubble`, `MessageInput`,
|
|
99
|
+
`PatientHeader`, `ChannelSettings`, etc.
|
|
100
|
+
|
|
101
|
+
## `CollabConfig` reference
|
|
102
|
+
|
|
103
|
+
| Field | Type | Notes |
|
|
104
|
+
| ------------- | ----------------------------------------------- | ------------------------------------------------ |
|
|
105
|
+
| `socketUrl` | `string` | Phoenix WebSocket endpoint. |
|
|
106
|
+
| `getToken` | `() => string` | Returns the current JWT. Re-read each connect. |
|
|
107
|
+
| `userId` | `string` | Must match your backend's user identity. |
|
|
108
|
+
| `userRole` | `'lab' \| 'radiologist' \| 'physician' \| 'admin'` | |
|
|
109
|
+
| `userName` | `string` | Displayed in messages and presence. |
|
|
110
|
+
| `userAvatar` | `string?` | Optional avatar URL. |
|
|
111
|
+
| `onOpenDicom` | `(studyId, storageId) => void` | Opens the host's DICOM viewer. Gates the button. |
|
|
112
|
+
| `onUploadFile`| `(file, fileName?) => Promise<string>` | Returns a public URL after upload. |
|
|
113
|
+
| `onDeepLink` | `(path: string) => void` | Resolves `natoe://...` links inside messages. |
|
|
114
|
+
| `onError` | `(err: CollabError) => void` | Centralized error sink. |
|
|
115
|
+
|
|
116
|
+
## `PatientData` reference
|
|
117
|
+
|
|
118
|
+
Conversations are study-aware. Pass a `PatientData` object per chat surface so
|
|
119
|
+
the header and "View DICOM" button render with the right context.
|
|
120
|
+
|
|
121
|
+
| Field | Required | Notes |
|
|
122
|
+
| -------------------- | -------- | -------------------------------------------------------- |
|
|
123
|
+
| `orderId` | yes | Stable per-case identifier. |
|
|
124
|
+
| `patientName` | yes | |
|
|
125
|
+
| `studyId` | no | PACS study UID. Pair with `storageId` to show "View DICOM". |
|
|
126
|
+
| `storageId` | no | e.g. `'PACS'`. Required alongside `studyId`. |
|
|
127
|
+
| `patientAge`, `patientSex`, `studyType`, `bodyParts`, `referringPhysician`, `labName`, `displayOrderId` | no | Header chrome. |
|
|
128
|
+
|
|
129
|
+
## How conversations are created
|
|
130
|
+
|
|
131
|
+
A conversation is materialized the first time someone sends a message — empty
|
|
132
|
+
chats don't clutter the inbox. After that first message, anyone with access to
|
|
133
|
+
the case can join.
|
|
134
|
+
|
|
135
|
+
Who can send the first message:
|
|
136
|
+
|
|
137
|
+
- **Lab / Admin** — any case
|
|
138
|
+
- **Radiologist** — only after being assigned
|
|
139
|
+
- **Physician** — only after the case is completed
|
|
140
|
+
|
|
141
|
+
When a new role joins (e.g. an assigned radiologist), they see the full
|
|
142
|
+
backlog from before they joined.
|
|
143
|
+
|
|
144
|
+
## Message types
|
|
145
|
+
|
|
146
|
+
Text, voice (record-and-send), images, files (up to 20 MB), system events,
|
|
147
|
+
and deep links (`natoe://...`) that the host app resolves via `onDeepLink`.
|
|
148
|
+
|
|
149
|
+
## Key features
|
|
150
|
+
|
|
151
|
+
- Reply to a specific message (frozen quote snapshot)
|
|
152
|
+
- Pin up to 3 messages per channel
|
|
153
|
+
- Read receipts ("Seen by …")
|
|
154
|
+
- Typing indicators (debounced)
|
|
155
|
+
- Unread counts per channel and total
|
|
156
|
+
- Channel settings: rename, picture, add/remove participants
|
|
157
|
+
|
|
158
|
+
## TypeScript
|
|
159
|
+
|
|
160
|
+
Fully typed. All public types are exported from the root:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import type {
|
|
164
|
+
CollabConfig,
|
|
165
|
+
PatientData,
|
|
166
|
+
Conversation,
|
|
167
|
+
Message,
|
|
168
|
+
Participant,
|
|
169
|
+
CollabError,
|
|
170
|
+
} from '@natoe/colab';
|
|
171
|
+
```
|