@hipnation-truth/sdk 0.5.0 → 0.7.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/dist/react.js CHANGED
@@ -47,6 +47,11 @@ __export(react_exports, {
47
47
  useAppointment: () => useAppointment,
48
48
  useAppointmentByElationId: () => useAppointmentByElationId,
49
49
  useAppointments: () => useAppointments,
50
+ useConversationByPhonePair: () => useConversationByPhonePair,
51
+ useConversationMessages: () => useConversationMessages,
52
+ useConversations: () => useConversations,
53
+ useMessages: () => useMessages,
54
+ useNotifications: () => useNotifications,
50
55
  usePatient: () => usePatient,
51
56
  usePatientBasic: () => usePatientBasic,
52
57
  usePatientByElationId: () => usePatientByElationId,
@@ -57,87 +62,145 @@ __export(react_exports, {
57
62
  usePharmacyByNcpdpId: () => usePharmacyByNcpdpId,
58
63
  usePhysicianByElationId: () => usePhysicianByElationId,
59
64
  usePhysiciansByElationIds: () => usePhysiciansByElationIds,
60
- useTruth: () => useTruth
65
+ useTruth: () => useTruth,
66
+ useUnreadCount: () => useUnreadCount
61
67
  });
62
68
  module.exports = __toCommonJS(react_exports);
63
69
 
64
- // src/react/hooks.ts
70
+ // src/react/conversations.ts
65
71
  var import_react = require("convex/react");
66
- var import_react2 = require("react");
67
72
  var import_server = require("convex/server");
68
- var patientsListRef = (0, import_server.makeFunctionReference)("patients:list");
69
- var patientsGetRef = (0, import_server.makeFunctionReference)("patients:get");
70
- var patientsByElationIdRef = (0, import_server.makeFunctionReference)("patients:getByElationId");
71
- var patientsByHintIdRef = (0, import_server.makeFunctionReference)("patients:getByHintId");
72
- var appointmentsListRef = (0, import_server.makeFunctionReference)("appointments:list");
73
- var appointmentsGetRef = (0, import_server.makeFunctionReference)("appointments:get");
74
- var appointmentsByElationIdRef = (0, import_server.makeFunctionReference)("appointments:getByElationId");
73
+ var conversationsListForUserRef = (0, import_server.makeFunctionReference)("conversations:listForUser");
74
+ var conversationsGetUnreadTotalForUserRef = (0, import_server.makeFunctionReference)("conversations:getUnreadTotalForUser");
75
+ var conversationsGetByPhonePairRef = (0, import_server.makeFunctionReference)("conversations:getByPhonePair");
76
+ var conversationMessagesGetByConversationIdRef = (0, import_server.makeFunctionReference)("conversationMessages:getByConversationId");
77
+ var SKIP = "skip";
78
+ function toResult(value, skipped) {
79
+ if (skipped) {
80
+ return { data: void 0, loading: false, error: void 0 };
81
+ }
82
+ return {
83
+ data: value,
84
+ loading: value === void 0,
85
+ error: void 0
86
+ };
87
+ }
88
+ function useConversations(filters) {
89
+ const skipped = !filters.userId;
90
+ const result = (0, import_react.useQuery)(
91
+ conversationsListForUserRef,
92
+ skipped ? SKIP : {
93
+ userId: filters.userId,
94
+ limit: filters.limit
95
+ }
96
+ );
97
+ return toResult(result, skipped);
98
+ }
99
+ function useConversationByPhonePair(phonePair) {
100
+ const skipped = !phonePair;
101
+ const result = (0, import_react.useQuery)(
102
+ conversationsGetByPhonePairRef,
103
+ skipped ? SKIP : { phonePair }
104
+ );
105
+ return toResult(result, skipped);
106
+ }
107
+ function useMessages(conversationId, options) {
108
+ const skipped = !conversationId;
109
+ const result = (0, import_react.useQuery)(
110
+ conversationMessagesGetByConversationIdRef,
111
+ skipped ? SKIP : {
112
+ conversationId,
113
+ limit: options == null ? void 0 : options.limit
114
+ }
115
+ );
116
+ return toResult(result, skipped);
117
+ }
118
+ function useUnreadCount(userId) {
119
+ const skipped = !userId;
120
+ const result = (0, import_react.useQuery)(
121
+ conversationsGetUnreadTotalForUserRef,
122
+ skipped ? SKIP : { userId }
123
+ );
124
+ return toResult(result, skipped);
125
+ }
126
+
127
+ // src/react/hooks.ts
128
+ var import_react2 = require("convex/react");
129
+ var import_react3 = require("react");
130
+ var import_server2 = require("convex/server");
131
+ var patientsListRef = (0, import_server2.makeFunctionReference)("patients:list");
132
+ var patientsGetRef = (0, import_server2.makeFunctionReference)("patients:get");
133
+ var patientsByElationIdRef = (0, import_server2.makeFunctionReference)("patients:getByElationId");
134
+ var patientsByHintIdRef = (0, import_server2.makeFunctionReference)("patients:getByHintId");
135
+ var appointmentsListRef = (0, import_server2.makeFunctionReference)("appointments:list");
136
+ var appointmentsGetRef = (0, import_server2.makeFunctionReference)("appointments:get");
137
+ var appointmentsByElationIdRef = (0, import_server2.makeFunctionReference)("appointments:getByElationId");
75
138
  function usePatients(options) {
76
- return (0, import_react.useQuery)(patientsListRef, options != null ? options : {});
139
+ return (0, import_react2.useQuery)(patientsListRef, options != null ? options : {});
77
140
  }
78
141
  function usePatient(id) {
79
- return (0, import_react.useQuery)(patientsGetRef, { id });
142
+ return (0, import_react2.useQuery)(patientsGetRef, { id });
80
143
  }
81
144
  function usePatientByElationId(elationId) {
82
- return (0, import_react.useQuery)(patientsByElationIdRef, {
145
+ return (0, import_react2.useQuery)(patientsByElationIdRef, {
83
146
  elationId
84
147
  });
85
148
  }
86
149
  function usePatientByHintId(hintId) {
87
- return (0, import_react.useQuery)(patientsByHintIdRef, {
150
+ return (0, import_react2.useQuery)(patientsByHintIdRef, {
88
151
  hintId
89
152
  });
90
153
  }
91
154
  function useAppointments(options) {
92
- return (0, import_react.useQuery)(
155
+ return (0, import_react2.useQuery)(
93
156
  appointmentsListRef,
94
157
  options != null ? options : {}
95
158
  );
96
159
  }
97
160
  function useAppointment(id) {
98
- return (0, import_react.useQuery)(appointmentsGetRef, { id });
161
+ return (0, import_react2.useQuery)(appointmentsGetRef, { id });
99
162
  }
100
163
  function useAppointmentByElationId(elationId) {
101
- return (0, import_react.useQuery)(appointmentsByElationIdRef, {
164
+ return (0, import_react2.useQuery)(appointmentsByElationIdRef, {
102
165
  elationId
103
166
  });
104
167
  }
105
- var physiciansGetByElationIdsRef = (0, import_server.makeFunctionReference)("physicians:getByElationIds");
106
- var physiciansGetByElationIdRef = (0, import_server.makeFunctionReference)("physicians:getByElationId");
168
+ var physiciansGetByElationIdsRef = (0, import_server2.makeFunctionReference)("physicians:getByElationIds");
169
+ var physiciansGetByElationIdRef = (0, import_server2.makeFunctionReference)("physicians:getByElationId");
107
170
  function usePhysiciansByElationIds(ids) {
108
- return (0, import_react.useQuery)(
171
+ return (0, import_react2.useQuery)(
109
172
  physiciansGetByElationIdsRef,
110
173
  ids && ids.length > 0 ? { ids } : "skip"
111
174
  );
112
175
  }
113
176
  function usePhysicianByElationId(id) {
114
- return (0, import_react.useQuery)(
177
+ return (0, import_react2.useQuery)(
115
178
  physiciansGetByElationIdRef,
116
179
  id !== void 0 ? { id } : "skip"
117
180
  );
118
181
  }
119
- var medicationsByPatientRef = (0, import_server.makeFunctionReference)("medicalRecords:getMedicationsByElationPatient");
120
- var problemsByPatientRef = (0, import_server.makeFunctionReference)("medicalRecords:getProblemsByElationPatient");
121
- var allergiesByPatientRef = (0, import_server.makeFunctionReference)("medicalRecords:getAllergiesByElationPatient");
122
- var appointmentsByPatientRef = (0, import_server.makeFunctionReference)("medicalRecords:getAppointmentsByElationPatient");
182
+ var medicationsByPatientRef = (0, import_server2.makeFunctionReference)("medicalRecords:getMedicationsByElationPatient");
183
+ var problemsByPatientRef = (0, import_server2.makeFunctionReference)("medicalRecords:getProblemsByElationPatient");
184
+ var allergiesByPatientRef = (0, import_server2.makeFunctionReference)("medicalRecords:getAllergiesByElationPatient");
185
+ var appointmentsByPatientRef = (0, import_server2.makeFunctionReference)("medicalRecords:getAppointmentsByElationPatient");
123
186
  function usePatientMedical(elationId, options) {
124
- const medications = (0, import_react.useQuery)(
187
+ const medications = (0, import_react2.useQuery)(
125
188
  medicationsByPatientRef,
126
189
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
127
190
  );
128
- const problems = (0, import_react.useQuery)(
191
+ const problems = (0, import_react2.useQuery)(
129
192
  problemsByPatientRef,
130
193
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
131
194
  );
132
- const allergies = (0, import_react.useQuery)(
195
+ const allergies = (0, import_react2.useQuery)(
133
196
  allergiesByPatientRef,
134
197
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
135
198
  );
136
- const appointments = (0, import_react.useQuery)(
199
+ const appointments = (0, import_react2.useQuery)(
137
200
  appointmentsByPatientRef,
138
201
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
139
202
  );
140
- (0, import_react2.useEffect)(() => {
203
+ (0, import_react3.useEffect)(() => {
141
204
  if (elationId === void 0 || (options == null ? void 0 : options.skipRefresh)) {
142
205
  return;
143
206
  }
@@ -161,26 +224,32 @@ function usePatientMedical(elationId, options) {
161
224
  }, [elationId, options == null ? void 0 : options.apiBaseUrl, options == null ? void 0 : options.apiKey, options == null ? void 0 : options.skipRefresh]);
162
225
  return { medications, problems, allergies, appointments };
163
226
  }
164
- var elationPatientByIdRef = (0, import_server.makeFunctionReference)("elationPatients:getByElationId");
165
- var hintPatientByIdRef = (0, import_server.makeFunctionReference)("hintPatients:getByHintId");
166
- var pharmacyByNcpdpRef = (0, import_server.makeFunctionReference)("elationPharmacies:getByNcpdpId");
167
- var patientPhotoByIdRef = (0, import_server.makeFunctionReference)("elationPatientPhotos:getByElationPatientId");
227
+ var elationPatientByIdRef = (0, import_server2.makeFunctionReference)("elationPatients:getByElationId");
228
+ var hintPatientByIdRef = (0, import_server2.makeFunctionReference)("hintPatients:getByHintId");
229
+ var pharmacyByNcpdpRef = (0, import_server2.makeFunctionReference)("elationPharmacies:getByNcpdpId");
230
+ var patientPhotoByIdRef = (0, import_server2.makeFunctionReference)("elationPatientPhotos:getByElationPatientId");
168
231
  function usePatientBasic(input, options) {
169
232
  var _a, _b;
170
- const elationRow = (0, import_react.useQuery)(
233
+ const elationRow = (0, import_react2.useQuery)(
171
234
  elationPatientByIdRef,
172
235
  input.elationId !== void 0 ? { elationId: input.elationId } : "skip"
173
236
  );
174
- const hintRow = (0, import_react.useQuery)(
237
+ const hintRow = (0, import_react2.useQuery)(
175
238
  hintPatientByIdRef,
176
239
  input.hintId !== void 0 ? { hintId: input.hintId } : "skip"
177
240
  );
178
- (0, import_react2.useEffect)(() => {
179
- if (options == null ? void 0 : options.skipRefresh) return;
180
- if (!input.hintId && input.elationId === void 0) return;
241
+ (0, import_react3.useEffect)(() => {
242
+ if (options == null ? void 0 : options.skipRefresh) {
243
+ return;
244
+ }
245
+ if (!input.hintId && input.elationId === void 0) {
246
+ return;
247
+ }
181
248
  const apiBaseUrl = options == null ? void 0 : options.apiBaseUrl;
182
249
  const apiKey = options == null ? void 0 : options.apiKey;
183
- if (!apiBaseUrl || !apiKey) return;
250
+ if (!apiBaseUrl || !apiKey) {
251
+ return;
252
+ }
184
253
  const controller = new AbortController();
185
254
  void fetch(`${apiBaseUrl}/api/patients/basic/refresh`, {
186
255
  method: "POST",
@@ -216,22 +285,28 @@ function usePatientBasic(input, options) {
216
285
  };
217
286
  }
218
287
  function usePharmacyByNcpdpId(ncpdpId) {
219
- return (0, import_react.useQuery)(
288
+ return (0, import_react2.useQuery)(
220
289
  pharmacyByNcpdpRef,
221
290
  ncpdpId ? { ncpdpId } : "skip"
222
291
  );
223
292
  }
224
293
  function usePatientPhoto(elationId, options) {
225
- const photo = (0, import_react.useQuery)(
294
+ const photo = (0, import_react2.useQuery)(
226
295
  patientPhotoByIdRef,
227
296
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
228
297
  );
229
- (0, import_react2.useEffect)(() => {
230
- if (options == null ? void 0 : options.skipRefresh) return;
231
- if (elationId === void 0) return;
298
+ (0, import_react3.useEffect)(() => {
299
+ if (options == null ? void 0 : options.skipRefresh) {
300
+ return;
301
+ }
302
+ if (elationId === void 0) {
303
+ return;
304
+ }
232
305
  const apiBaseUrl = options == null ? void 0 : options.apiBaseUrl;
233
306
  const apiKey = options == null ? void 0 : options.apiKey;
234
- if (!apiBaseUrl || !apiKey) return;
307
+ if (!apiBaseUrl || !apiKey) {
308
+ return;
309
+ }
235
310
  const controller = new AbortController();
236
311
  void fetch(`${apiBaseUrl}/api/patients/photo/refresh`, {
237
312
  method: "POST",
@@ -247,10 +322,410 @@ function usePatientPhoto(elationId, options) {
247
322
  }, [elationId, options == null ? void 0 : options.apiBaseUrl, options == null ? void 0 : options.apiKey, options == null ? void 0 : options.skipRefresh]);
248
323
  return photo;
249
324
  }
325
+ var messagesByPhonesRef = (0, import_server2.makeFunctionReference)("conversationMessages:getByPhones");
326
+ var messagesByConversationIdRef = (0, import_server2.makeFunctionReference)("conversationMessages:getByConversationId");
327
+ function useConversationMessages(input, options) {
328
+ const hasPair = !!input.phoneA && !!input.phoneB;
329
+ const byPair = (0, import_react2.useQuery)(
330
+ messagesByPhonesRef,
331
+ hasPair ? {
332
+ phoneA: input.phoneA,
333
+ phoneB: input.phoneB,
334
+ limit: options == null ? void 0 : options.limit
335
+ } : "skip"
336
+ );
337
+ const byConvo = (0, import_react2.useQuery)(
338
+ messagesByConversationIdRef,
339
+ !hasPair && input.conversationId ? { conversationId: input.conversationId, limit: options == null ? void 0 : options.limit } : "skip"
340
+ );
341
+ return hasPair ? byPair : byConvo;
342
+ }
250
343
 
251
- // src/react/provider.ts
252
- var import_react3 = require("convex/react");
344
+ // src/react/notifications.ts
253
345
  var import_react4 = require("react");
346
+
347
+ // src/web-push.ts
348
+ function isWebPushSupported() {
349
+ return typeof window !== "undefined" && "serviceWorker" in navigator && "PushManager" in window;
350
+ }
351
+ function registerServiceWorker(path = "/truth-sw.js") {
352
+ return __async(this, null, function* () {
353
+ return navigator.serviceWorker.register(path);
354
+ });
355
+ }
356
+ function subscribeToPush(registration, vapidPublicKey) {
357
+ return __async(this, null, function* () {
358
+ const existing = yield registration.pushManager.getSubscription();
359
+ if (existing) {
360
+ return existing;
361
+ }
362
+ return registration.pushManager.subscribe({
363
+ userVisibleOnly: true,
364
+ applicationServerKey: urlBase64ToUint8Array(
365
+ vapidPublicKey
366
+ )
367
+ });
368
+ });
369
+ }
370
+ function subscriptionToJSON(sub) {
371
+ var _a, _b, _c, _d;
372
+ const json = sub.toJSON();
373
+ return {
374
+ endpoint: sub.endpoint,
375
+ keys: {
376
+ p256dh: (_b = (_a = json.keys) == null ? void 0 : _a.p256dh) != null ? _b : "",
377
+ auth: (_d = (_c = json.keys) == null ? void 0 : _c.auth) != null ? _d : ""
378
+ }
379
+ };
380
+ }
381
+ function urlBase64ToUint8Array(base64String) {
382
+ const padding = "=".repeat((4 - base64String.length % 4) % 4);
383
+ const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
384
+ const rawData = atob(base64);
385
+ const outputArray = new Uint8Array(rawData.length);
386
+ for (let i = 0; i < rawData.length; ++i) {
387
+ outputArray[i] = rawData.charCodeAt(i);
388
+ }
389
+ return outputArray;
390
+ }
391
+
392
+ // src/react/notifications.ts
393
+ function loadExpo() {
394
+ return __async(this, null, function* () {
395
+ try {
396
+ const modName = "expo-notifications";
397
+ return yield import(
398
+ /* @vite-ignore */
399
+ /* webpackIgnore: true */
400
+ modName
401
+ );
402
+ } catch (e) {
403
+ return null;
404
+ }
405
+ });
406
+ }
407
+ function useNotifications(options) {
408
+ var _a;
409
+ const [permissionStatus, setPermissionStatus] = (0, import_react4.useState)("unknown");
410
+ const [devicePushToken, setDevicePushToken] = (0, import_react4.useState)(null);
411
+ const expoRef = (0, import_react4.useRef)(null);
412
+ const isWebRef = (0, import_react4.useRef)(false);
413
+ const vapidKeyRef = (0, import_react4.useRef)((_a = options.vapidPublicKey) != null ? _a : null);
414
+ (0, import_react4.useEffect)(() => {
415
+ let mounted = true;
416
+ void (() => __async(null, null, function* () {
417
+ var _a2;
418
+ const expo = yield loadExpo();
419
+ if (!mounted) {
420
+ return;
421
+ }
422
+ expoRef.current = expo;
423
+ if (expo) {
424
+ try {
425
+ const perm = yield expo.getPermissionsAsync();
426
+ if (!mounted) {
427
+ return;
428
+ }
429
+ setPermissionStatus(mapStatus(perm == null ? void 0 : perm.status));
430
+ } catch (e) {
431
+ setPermissionStatus("unknown");
432
+ }
433
+ return;
434
+ }
435
+ if (isWebPushSupported()) {
436
+ isWebRef.current = true;
437
+ if (!vapidKeyRef.current) {
438
+ try {
439
+ const res = yield fetch(
440
+ `${options.apiBaseUrl}/api/notifications/vapid-key`,
441
+ {
442
+ headers: {
443
+ Accept: "application/json",
444
+ "X-API-Key": options.apiKey
445
+ }
446
+ }
447
+ );
448
+ if (res.ok) {
449
+ const data = yield res.json();
450
+ vapidKeyRef.current = (_a2 = data.vapidPublicKey) != null ? _a2 : null;
451
+ }
452
+ } catch (e) {
453
+ }
454
+ }
455
+ if (!mounted) {
456
+ return;
457
+ }
458
+ const webPerm = typeof Notification !== "undefined" ? Notification.permission : "default";
459
+ setPermissionStatus(
460
+ webPerm === "granted" ? "granted" : webPerm === "denied" ? "denied" : "undetermined"
461
+ );
462
+ } else {
463
+ setPermissionStatus("unknown");
464
+ }
465
+ }))();
466
+ return () => {
467
+ mounted = false;
468
+ };
469
+ }, [options.apiBaseUrl, options.apiKey]);
470
+ const register = (0, import_react4.useCallback)(() => __async(null, null, function* () {
471
+ var _a2, _b;
472
+ if (!options.userId) {
473
+ return { ok: false, reason: "missing_userId" };
474
+ }
475
+ if (isWebRef.current) {
476
+ const vapidKey = vapidKeyRef.current;
477
+ if (!vapidKey) {
478
+ return { ok: false, reason: "no_vapid_key" };
479
+ }
480
+ const webPerm = yield Notification.requestPermission();
481
+ setPermissionStatus(
482
+ webPerm === "granted" ? "granted" : webPerm === "denied" ? "denied" : "undetermined"
483
+ );
484
+ if (webPerm !== "granted") {
485
+ return { ok: false, reason: "permission_denied" };
486
+ }
487
+ try {
488
+ const swPath = (_a2 = options.serviceWorkerPath) != null ? _a2 : "/truth-sw.js";
489
+ const registration = yield registerServiceWorker(swPath);
490
+ yield navigator.serviceWorker.ready;
491
+ const subscription = yield subscribeToPush(registration, vapidKey);
492
+ const subJSON = subscriptionToJSON(subscription);
493
+ setDevicePushToken(subscription.endpoint);
494
+ const res2 = yield fetch(
495
+ `${options.apiBaseUrl}/api/notifications/devices/register`,
496
+ {
497
+ method: "POST",
498
+ headers: {
499
+ "Content-Type": "application/json",
500
+ "X-API-Key": options.apiKey
501
+ },
502
+ body: JSON.stringify({
503
+ userId: options.userId,
504
+ platform: "web",
505
+ webPushSubscription: subJSON,
506
+ appVersion: options.appVersion,
507
+ locale: navigator.language,
508
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
509
+ })
510
+ }
511
+ );
512
+ if (!res2.ok) {
513
+ const text = yield res2.text().catch(() => "");
514
+ return {
515
+ ok: false,
516
+ reason: `register_failed_${res2.status}: ${text.slice(0, 120)}`
517
+ };
518
+ }
519
+ return { ok: true };
520
+ } catch (err) {
521
+ return {
522
+ ok: false,
523
+ reason: `web_push_error: ${err instanceof Error ? err.message : String(err)}`
524
+ };
525
+ }
526
+ }
527
+ const expo = (_b = expoRef.current) != null ? _b : yield loadExpo();
528
+ expoRef.current = expo;
529
+ if (!expo) {
530
+ return { ok: false, reason: "expo_notifications_missing" };
531
+ }
532
+ let perm = yield expo.getPermissionsAsync();
533
+ if ((perm == null ? void 0 : perm.status) !== "granted") {
534
+ perm = yield expo.requestPermissionsAsync();
535
+ }
536
+ setPermissionStatus(mapStatus(perm == null ? void 0 : perm.status));
537
+ if ((perm == null ? void 0 : perm.status) !== "granted") {
538
+ return { ok: false, reason: "permission_denied" };
539
+ }
540
+ const tokenResp = yield expo.getDevicePushTokenAsync();
541
+ const nativeToken = tokenResp == null ? void 0 : tokenResp.data;
542
+ const platform = detectPlatform(tokenResp == null ? void 0 : tokenResp.type);
543
+ if (!nativeToken || platform !== "ios" && platform !== "android") {
544
+ return { ok: false, reason: "no_native_token" };
545
+ }
546
+ setDevicePushToken(nativeToken);
547
+ const res = yield fetch(
548
+ `${options.apiBaseUrl}/api/notifications/devices/register`,
549
+ {
550
+ method: "POST",
551
+ headers: {
552
+ "Content-Type": "application/json",
553
+ "X-API-Key": options.apiKey
554
+ },
555
+ body: JSON.stringify({
556
+ userId: options.userId,
557
+ platform,
558
+ nativeToken,
559
+ appVersion: options.appVersion,
560
+ locale: typeof navigator !== "undefined" ? navigator.language : void 0,
561
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
562
+ })
563
+ }
564
+ );
565
+ if (!res.ok) {
566
+ const text = yield res.text().catch(() => "");
567
+ return {
568
+ ok: false,
569
+ reason: `register_failed_${res.status}: ${text.slice(0, 120)}`
570
+ };
571
+ }
572
+ return { ok: true };
573
+ }), [
574
+ options.apiBaseUrl,
575
+ options.apiKey,
576
+ options.userId,
577
+ options.appVersion,
578
+ options.serviceWorkerPath
579
+ ]);
580
+ const unregister = (0, import_react4.useCallback)(() => __async(null, null, function* () {
581
+ if (!devicePushToken) {
582
+ return;
583
+ }
584
+ yield fetch(`${options.apiBaseUrl}/api/notifications/devices/unregister`, {
585
+ method: "POST",
586
+ headers: {
587
+ "Content-Type": "application/json",
588
+ "X-API-Key": options.apiKey
589
+ },
590
+ body: JSON.stringify({ nativeToken: devicePushToken })
591
+ }).catch(() => {
592
+ });
593
+ setDevicePushToken(null);
594
+ }), [options.apiBaseUrl, options.apiKey, devicePushToken]);
595
+ const addReceivedListener = (0, import_react4.useCallback)(
596
+ (listener) => {
597
+ if (isWebRef.current) {
598
+ if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
599
+ return () => {
600
+ };
601
+ }
602
+ const handler = (event) => {
603
+ var _a2;
604
+ if (((_a2 = event.data) == null ? void 0 : _a2.type) === "TRUTH_PUSH_RECEIVED") {
605
+ listener(event.data.payload);
606
+ }
607
+ };
608
+ navigator.serviceWorker.addEventListener("message", handler);
609
+ return () => navigator.serviceWorker.removeEventListener("message", handler);
610
+ }
611
+ const expo = expoRef.current;
612
+ if (!(expo == null ? void 0 : expo.addNotificationReceivedListener)) {
613
+ return () => {
614
+ };
615
+ }
616
+ const sub = expo.addNotificationReceivedListener(listener);
617
+ return () => {
618
+ var _a2;
619
+ return (_a2 = sub.remove) == null ? void 0 : _a2.call(sub);
620
+ };
621
+ },
622
+ []
623
+ );
624
+ const addResponseListener = (0, import_react4.useCallback)(
625
+ (listener) => {
626
+ if (isWebRef.current) {
627
+ if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
628
+ return () => {
629
+ };
630
+ }
631
+ const handler = (event) => {
632
+ var _a2;
633
+ if (((_a2 = event.data) == null ? void 0 : _a2.type) === "TRUTH_PUSH_TAPPED") {
634
+ listener(event.data.payload);
635
+ }
636
+ };
637
+ navigator.serviceWorker.addEventListener("message", handler);
638
+ return () => navigator.serviceWorker.removeEventListener("message", handler);
639
+ }
640
+ const expo = expoRef.current;
641
+ if (!(expo == null ? void 0 : expo.addNotificationResponseReceivedListener)) {
642
+ return () => {
643
+ };
644
+ }
645
+ const sub = expo.addNotificationResponseReceivedListener(listener);
646
+ return () => {
647
+ var _a2;
648
+ return (_a2 = sub.remove) == null ? void 0 : _a2.call(sub);
649
+ };
650
+ },
651
+ []
652
+ );
653
+ const getBadgeCount = (0, import_react4.useCallback)(() => __async(null, null, function* () {
654
+ var _a2;
655
+ const expo = expoRef.current;
656
+ if (!(expo == null ? void 0 : expo.getBadgeCountAsync)) {
657
+ return 0;
658
+ }
659
+ return (_a2 = yield expo.getBadgeCountAsync()) != null ? _a2 : 0;
660
+ }), []);
661
+ const setBadgeCount = (0, import_react4.useCallback)((count) => __async(null, null, function* () {
662
+ const expo = expoRef.current;
663
+ if (!(expo == null ? void 0 : expo.setBadgeCountAsync)) {
664
+ return;
665
+ }
666
+ yield expo.setBadgeCountAsync(count);
667
+ }), []);
668
+ const autoRegister = options.autoRegister !== false;
669
+ (0, import_react4.useEffect)(() => {
670
+ if (!autoRegister) {
671
+ return;
672
+ }
673
+ if (permissionStatus !== "granted") {
674
+ return;
675
+ }
676
+ if (devicePushToken) {
677
+ return;
678
+ }
679
+ if (!options.userId) {
680
+ return;
681
+ }
682
+ void register();
683
+ }, [
684
+ autoRegister,
685
+ permissionStatus,
686
+ devicePushToken,
687
+ options.userId,
688
+ register
689
+ ]);
690
+ return {
691
+ permissionStatus,
692
+ devicePushToken,
693
+ register,
694
+ unregister,
695
+ addReceivedListener,
696
+ addResponseListener,
697
+ getBadgeCount,
698
+ setBadgeCount
699
+ };
700
+ }
701
+ function mapStatus(status) {
702
+ if (status === "granted") {
703
+ return "granted";
704
+ }
705
+ if (status === "denied") {
706
+ return "denied";
707
+ }
708
+ if (status === "undetermined") {
709
+ return "undetermined";
710
+ }
711
+ return "unknown";
712
+ }
713
+ function detectPlatform(tokenType) {
714
+ if (tokenType === "apns") {
715
+ return "ios";
716
+ }
717
+ if (tokenType === "fcm") {
718
+ return "android";
719
+ }
720
+ if (tokenType === "web") {
721
+ return "web";
722
+ }
723
+ return "unknown";
724
+ }
725
+
726
+ // src/react/provider.ts
727
+ var import_react5 = require("convex/react");
728
+ var import_react6 = require("react");
254
729
  var CONVEX_URLS = {
255
730
  local: "https://courteous-duck-623.convex.cloud",
256
731
  staging: "https://courteous-duck-623.convex.cloud",
@@ -259,19 +734,26 @@ var CONVEX_URLS = {
259
734
  uat: "https://gallant-gecko-217.convex.cloud",
260
735
  production: "https://gallant-gecko-217.convex.cloud"
261
736
  };
737
+ function resolveConvexUrl(environment, override) {
738
+ var _a;
739
+ if (override) {
740
+ return override;
741
+ }
742
+ const env = environment != null ? environment : "sandbox";
743
+ return (_a = CONVEX_URLS[env]) != null ? _a : CONVEX_URLS.sandbox;
744
+ }
262
745
  function TruthProvider({
263
746
  environment = "sandbox",
264
747
  convexUrl,
265
748
  children
266
749
  }) {
267
- var _a;
268
- const url = (_a = convexUrl != null ? convexUrl : CONVEX_URLS[environment]) != null ? _a : CONVEX_URLS.sandbox;
269
- const client = (0, import_react4.useMemo)(() => new import_react3.ConvexReactClient(url), [url]);
270
- return (0, import_react4.createElement)(import_react3.ConvexProvider, { client }, children);
750
+ const url = resolveConvexUrl(environment, convexUrl);
751
+ const client = (0, import_react6.useMemo)(() => new import_react5.ConvexReactClient(url), [url]);
752
+ return (0, import_react6.createElement)(import_react5.ConvexProvider, { client }, children);
271
753
  }
272
754
 
273
755
  // src/react/tracking.ts
274
- var import_react5 = require("react");
756
+ var import_react7 = require("react");
275
757
 
276
758
  // src/tracking/tracker.ts
277
759
  function generateUuidV7() {
@@ -466,7 +948,7 @@ function sleep(ms) {
466
948
  }
467
949
 
468
950
  // src/react/tracking.ts
469
- var TruthTrackingContext = (0, import_react5.createContext)(
951
+ var TruthTrackingContext = (0, import_react7.createContext)(
470
952
  null
471
953
  );
472
954
  function TruthTrackingProvider({
@@ -477,7 +959,7 @@ function TruthTrackingProvider({
477
959
  apiKey = "",
478
960
  children
479
961
  }) {
480
- const value = (0, import_react5.useMemo)(() => {
962
+ const value = (0, import_react7.useMemo)(() => {
481
963
  const tracker = new Tracker({
482
964
  apiKey,
483
965
  environment,
@@ -496,10 +978,10 @@ function TruthTrackingProvider({
496
978
  }
497
979
  };
498
980
  }, [apiKey, environment, source, sourceVersion, tenantId]);
499
- return (0, import_react5.createElement)(TruthTrackingContext.Provider, { value }, children);
981
+ return (0, import_react7.createElement)(TruthTrackingContext.Provider, { value }, children);
500
982
  }
501
983
  function useTruth() {
502
- const ctx = (0, import_react5.useContext)(TruthTrackingContext);
984
+ const ctx = (0, import_react7.useContext)(TruthTrackingContext);
503
985
  if (!ctx) {
504
986
  throw new Error("useTruth must be used within a TruthTrackingProvider");
505
987
  }
@@ -512,6 +994,11 @@ function useTruth() {
512
994
  useAppointment,
513
995
  useAppointmentByElationId,
514
996
  useAppointments,
997
+ useConversationByPhonePair,
998
+ useConversationMessages,
999
+ useConversations,
1000
+ useMessages,
1001
+ useNotifications,
515
1002
  usePatient,
516
1003
  usePatientBasic,
517
1004
  usePatientByElationId,
@@ -522,6 +1009,7 @@ function useTruth() {
522
1009
  usePharmacyByNcpdpId,
523
1010
  usePhysicianByElationId,
524
1011
  usePhysiciansByElationIds,
525
- useTruth
1012
+ useTruth,
1013
+ useUnreadCount
526
1014
  });
527
1015
  //# sourceMappingURL=react.js.map