@blackcode_sa/metaestetics-api 1.5.43 → 1.5.45

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.
@@ -5,8 +5,8 @@ import {
5
5
  updateDoc,
6
6
  arrayUnion,
7
7
  serverTimestamp,
8
- } from 'firebase/firestore';
9
- import { BaseService } from '../base.service';
8
+ } from "firebase/firestore";
9
+ import { BaseService } from "../base.service";
10
10
  import {
11
11
  PatientProfile,
12
12
  PatientSensitiveInfo,
@@ -31,11 +31,11 @@ import {
31
31
  PatientClinic,
32
32
  SearchPatientsParams,
33
33
  RequesterInfo,
34
- } from '../../types/patient';
35
- import { Auth } from 'firebase/auth';
36
- import { Firestore } from 'firebase/firestore';
37
- import { FirebaseApp } from 'firebase/app';
38
- import { Timestamp } from 'firebase/firestore';
34
+ } from "../../types/patient";
35
+ import { Auth } from "firebase/auth";
36
+ import { Firestore } from "firebase/firestore";
37
+ import { FirebaseApp } from "firebase/app";
38
+ import { Timestamp } from "firebase/firestore";
39
39
 
40
40
  // Importujemo utility funkcije
41
41
  import {
@@ -52,20 +52,20 @@ import {
52
52
  updatePatientProfileByUserRefUtil,
53
53
  searchPatientsUtil,
54
54
  getAllPatientsUtil,
55
- } from './utils/profile.utils';
55
+ } from "./utils/profile.utils";
56
56
 
57
57
  import {
58
58
  updatePatientLocationUtil,
59
59
  createLocationInfoUtil,
60
60
  getLocationInfoUtil,
61
61
  updateLocationInfoUtil,
62
- } from './utils/location.utils';
62
+ } from "./utils/location.utils";
63
63
 
64
64
  import {
65
65
  createSensitiveInfoUtil,
66
66
  getSensitiveInfoUtil,
67
67
  updateSensitiveInfoUtil,
68
- } from './utils/sensitive.utils';
68
+ } from "./utils/sensitive.utils";
69
69
 
70
70
  import {
71
71
  createMedicalInfoUtil,
@@ -83,21 +83,24 @@ import {
83
83
  addMedicationUtil,
84
84
  updateMedicationUtil,
85
85
  removeMedicationUtil,
86
- } from './utils/medical.utils';
86
+ } from "./utils/medical.utils";
87
87
 
88
88
  import {
89
89
  getPatientDocRef,
90
90
  getSensitiveInfoDocRef,
91
91
  getLocationInfoDocRef,
92
92
  getMedicalInfoDocRef,
93
- } from './utils/docs.utils';
93
+ } from "./utils/docs.utils";
94
94
 
95
95
  import {
96
96
  addDoctorUtil,
97
97
  removeDoctorUtil,
98
98
  addClinicUtil,
99
99
  removeClinicUtil,
100
- } from './utils/medical-stuff.utils';
100
+ } from "./utils/medical-stuff.utils";
101
+
102
+ import { getPatientsByPractitionerUtil } from "./utils/practitioner.utils";
103
+ import { getPatientsByClinicUtil } from "./utils/clinic.utils";
101
104
 
102
105
  export class PatientService extends BaseService {
103
106
  constructor(db: Firestore, auth: Auth, app: FirebaseApp) {
@@ -105,7 +108,9 @@ export class PatientService extends BaseService {
105
108
  }
106
109
 
107
110
  // Metode za rad sa profilom pacijenta
108
- async createPatientProfile(data: CreatePatientProfileData): Promise<PatientProfile> {
111
+ async createPatientProfile(
112
+ data: CreatePatientProfileData
113
+ ): Promise<PatientProfile> {
109
114
  return createPatientProfileUtil(this.db, data, () => this.generateId());
110
115
  }
111
116
 
@@ -113,7 +118,9 @@ export class PatientService extends BaseService {
113
118
  return getPatientProfileUtil(this.db, patientId);
114
119
  }
115
120
 
116
- async getPatientProfileByUserRef(userRef: string): Promise<PatientProfile | null> {
121
+ async getPatientProfileByUserRef(
122
+ userRef: string
123
+ ): Promise<PatientProfile | null> {
117
124
  return getPatientProfileByUserRefUtil(this.db, userRef);
118
125
  }
119
126
 
@@ -121,7 +128,7 @@ export class PatientService extends BaseService {
121
128
  async updatePatientLocation(
122
129
  patientId: string,
123
130
  latitude: number,
124
- longitude: number,
131
+ longitude: number
125
132
  ): Promise<void> {
126
133
  await updatePatientLocationUtil(this.db, patientId, latitude, longitude);
127
134
  }
@@ -129,30 +136,30 @@ export class PatientService extends BaseService {
129
136
  async updatePatientLocationByUserRef(
130
137
  userRef: string,
131
138
  latitude: number,
132
- longitude: number,
139
+ longitude: number
133
140
  ): Promise<void> {
134
141
  const profile = await this.getPatientProfileByUserRef(userRef);
135
- if (!profile) throw new Error('Patient profile not found');
142
+ if (!profile) throw new Error("Patient profile not found");
136
143
  await this.updatePatientLocation(profile.id, latitude, longitude);
137
144
  }
138
145
 
139
146
  async createLocationInfo(
140
147
  data: CreatePatientLocationInfoData,
141
- requesterId: string,
148
+ requesterId: string
142
149
  ): Promise<PatientLocationInfo> {
143
150
  return createLocationInfoUtil(this.db, data, requesterId);
144
151
  }
145
152
 
146
153
  async getLocationInfo(
147
154
  patientId: string,
148
- requesterId: string,
155
+ requesterId: string
149
156
  ): Promise<PatientLocationInfo | null> {
150
157
  return getLocationInfoUtil(this.db, patientId, requesterId);
151
158
  }
152
159
 
153
160
  async getLocationInfoByUserRef(
154
161
  userRef: string,
155
- requesterId: string,
162
+ requesterId: string
156
163
  ): Promise<PatientLocationInfo | null> {
157
164
  const profile = await this.getPatientProfileByUserRef(userRef);
158
165
  if (!profile) return null;
@@ -162,7 +169,7 @@ export class PatientService extends BaseService {
162
169
  async updateLocationInfo(
163
170
  patientId: string,
164
171
  data: UpdatePatientLocationInfoData,
165
- requesterId: string,
172
+ requesterId: string
166
173
  ): Promise<PatientLocationInfo> {
167
174
  return updateLocationInfoUtil(this.db, patientId, data, requesterId);
168
175
  }
@@ -170,21 +177,21 @@ export class PatientService extends BaseService {
170
177
  // Metode za rad sa osetljivim informacijama
171
178
  async createSensitiveInfo(
172
179
  data: CreatePatientSensitiveInfoData,
173
- requesterUserId: string,
180
+ requesterUserId: string
174
181
  ): Promise<PatientSensitiveInfo> {
175
182
  return createSensitiveInfoUtil(this.db, data, requesterUserId);
176
183
  }
177
184
 
178
185
  async getSensitiveInfo(
179
186
  patientId: string,
180
- requesterUserId: string,
187
+ requesterUserId: string
181
188
  ): Promise<PatientSensitiveInfo | null> {
182
189
  return getSensitiveInfoUtil(this.db, patientId, requesterUserId);
183
190
  }
184
191
 
185
192
  async getSensitiveInfoByUserRef(
186
193
  userRef: string,
187
- requesterUserId: string,
194
+ requesterUserId: string
188
195
  ): Promise<PatientSensitiveInfo | null> {
189
196
  const profile = await this.getPatientProfileByUserRef(userRef);
190
197
  if (!profile) return null;
@@ -194,30 +201,47 @@ export class PatientService extends BaseService {
194
201
  async updateSensitiveInfo(
195
202
  patientId: string,
196
203
  data: UpdatePatientSensitiveInfoData,
197
- requesterUserId: string,
204
+ requesterUserId: string
198
205
  ): Promise<PatientSensitiveInfo> {
199
206
  return updateSensitiveInfoUtil(this.db, patientId, data, requesterUserId);
200
207
  }
201
208
 
202
209
  // Metode za rad sa medicinskim informacijama
203
- async createMedicalInfo(patientId: string, data: CreatePatientMedicalInfoData): Promise<void> {
210
+ async createMedicalInfo(
211
+ patientId: string,
212
+ data: CreatePatientMedicalInfoData
213
+ ): Promise<void> {
204
214
  const currentUser = await this.getCurrentUser();
205
- await createMedicalInfoUtil(this.db, patientId, data, currentUser.uid, currentUser.roles);
215
+ await createMedicalInfoUtil(
216
+ this.db,
217
+ patientId,
218
+ data,
219
+ currentUser.uid,
220
+ currentUser.roles
221
+ );
206
222
  }
207
223
 
208
224
  async getMedicalInfo(patientId: string): Promise<PatientMedicalInfo> {
209
225
  const currentUser = await this.getCurrentUser();
210
- return getMedicalInfoUtil(this.db, patientId, currentUser.uid, currentUser.roles);
226
+ return getMedicalInfoUtil(
227
+ this.db,
228
+ patientId,
229
+ currentUser.uid,
230
+ currentUser.roles
231
+ );
211
232
  }
212
233
 
213
234
  async getMedicalInfoByUserRef(userRef: string): Promise<PatientMedicalInfo> {
214
235
  const profile = await this.getPatientProfileByUserRef(userRef);
215
- if (!profile) throw new Error('Patient profile not found');
236
+ if (!profile) throw new Error("Patient profile not found");
216
237
  return this.getMedicalInfo(profile.id);
217
238
  }
218
239
 
219
240
  // Metode za rad sa vitalnim statistikama
220
- async updateVitalStats(patientId: string, data: UpdateVitalStatsData): Promise<void> {
241
+ async updateVitalStats(
242
+ patientId: string,
243
+ data: UpdateVitalStatsData
244
+ ): Promise<void> {
221
245
  const currentUser = await this.getCurrentUser();
222
246
  await updateVitalStatsUtil(this.db, patientId, data, currentUser.uid);
223
247
  }
@@ -228,7 +252,10 @@ export class PatientService extends BaseService {
228
252
  await addAllergyUtil(this.db, patientId, data, currentUser.uid);
229
253
  }
230
254
 
231
- async updateAllergy(patientId: string, data: UpdateAllergyData): Promise<void> {
255
+ async updateAllergy(
256
+ patientId: string,
257
+ data: UpdateAllergyData
258
+ ): Promise<void> {
232
259
  const currentUser = await this.getCurrentUser();
233
260
  await updateAllergyUtil(this.db, patientId, data, currentUser.uid);
234
261
  }
@@ -239,54 +266,98 @@ export class PatientService extends BaseService {
239
266
  }
240
267
 
241
268
  // Metode za rad sa blocking conditions
242
- async addBlockingCondition(patientId: string, data: AddBlockingConditionData): Promise<void> {
269
+ async addBlockingCondition(
270
+ patientId: string,
271
+ data: AddBlockingConditionData
272
+ ): Promise<void> {
243
273
  const currentUser = await this.getCurrentUser();
244
274
  await addBlockingConditionUtil(this.db, patientId, data, currentUser.uid);
245
275
  }
246
276
 
247
277
  async updateBlockingCondition(
248
278
  patientId: string,
249
- data: UpdateBlockingConditionData,
279
+ data: UpdateBlockingConditionData
250
280
  ): Promise<void> {
251
281
  const currentUser = await this.getCurrentUser();
252
- await updateBlockingConditionUtil(this.db, patientId, data, currentUser.uid);
282
+ await updateBlockingConditionUtil(
283
+ this.db,
284
+ patientId,
285
+ data,
286
+ currentUser.uid
287
+ );
253
288
  }
254
289
 
255
- async removeBlockingCondition(patientId: string, conditionIndex: number): Promise<void> {
290
+ async removeBlockingCondition(
291
+ patientId: string,
292
+ conditionIndex: number
293
+ ): Promise<void> {
256
294
  const currentUser = await this.getCurrentUser();
257
- await removeBlockingConditionUtil(this.db, patientId, conditionIndex, currentUser.uid);
295
+ await removeBlockingConditionUtil(
296
+ this.db,
297
+ patientId,
298
+ conditionIndex,
299
+ currentUser.uid
300
+ );
258
301
  }
259
302
 
260
303
  // Metode za rad sa kontraindikacijama
261
- async addContraindication(patientId: string, data: AddContraindicationData): Promise<void> {
304
+ async addContraindication(
305
+ patientId: string,
306
+ data: AddContraindicationData
307
+ ): Promise<void> {
262
308
  const currentUser = await this.getCurrentUser();
263
309
  await addContraindicationUtil(this.db, patientId, data, currentUser.uid);
264
310
  }
265
311
 
266
- async updateContraindication(patientId: string, data: UpdateContraindicationData): Promise<void> {
312
+ async updateContraindication(
313
+ patientId: string,
314
+ data: UpdateContraindicationData
315
+ ): Promise<void> {
267
316
  const currentUser = await this.getCurrentUser();
268
317
  await updateContraindicationUtil(this.db, patientId, data, currentUser.uid);
269
318
  }
270
319
 
271
- async removeContraindication(patientId: string, contraindicationIndex: number): Promise<void> {
320
+ async removeContraindication(
321
+ patientId: string,
322
+ contraindicationIndex: number
323
+ ): Promise<void> {
272
324
  const currentUser = await this.getCurrentUser();
273
- await removeContraindicationUtil(this.db, patientId, contraindicationIndex, currentUser.uid);
325
+ await removeContraindicationUtil(
326
+ this.db,
327
+ patientId,
328
+ contraindicationIndex,
329
+ currentUser.uid
330
+ );
274
331
  }
275
332
 
276
333
  // Metode za rad sa medikacijama
277
- async addMedication(patientId: string, data: AddMedicationData): Promise<void> {
334
+ async addMedication(
335
+ patientId: string,
336
+ data: AddMedicationData
337
+ ): Promise<void> {
278
338
  const currentUser = await this.getCurrentUser();
279
339
  await addMedicationUtil(this.db, patientId, data, currentUser.uid);
280
340
  }
281
341
 
282
- async updateMedication(patientId: string, data: UpdateMedicationData): Promise<void> {
342
+ async updateMedication(
343
+ patientId: string,
344
+ data: UpdateMedicationData
345
+ ): Promise<void> {
283
346
  const currentUser = await this.getCurrentUser();
284
347
  await updateMedicationUtil(this.db, patientId, data, currentUser.uid);
285
348
  }
286
349
 
287
- async removeMedication(patientId: string, medicationIndex: number): Promise<void> {
350
+ async removeMedication(
351
+ patientId: string,
352
+ medicationIndex: number
353
+ ): Promise<void> {
288
354
  const currentUser = await this.getCurrentUser();
289
- await removeMedicationUtil(this.db, patientId, medicationIndex, currentUser.uid);
355
+ await removeMedicationUtil(
356
+ this.db,
357
+ patientId,
358
+ medicationIndex,
359
+ currentUser.uid
360
+ );
290
361
  }
291
362
 
292
363
  // Pomoćne metode
@@ -296,7 +367,7 @@ export class PatientService extends BaseService {
296
367
 
297
368
  async addExpoTokenByUserRef(userRef: string, token: string): Promise<void> {
298
369
  const profile = await this.getPatientProfileByUserRef(userRef);
299
- if (!profile) throw new Error('Patient profile not found');
370
+ if (!profile) throw new Error("Patient profile not found");
300
371
  await this.addExpoToken(profile.id, token);
301
372
  }
302
373
 
@@ -304,9 +375,12 @@ export class PatientService extends BaseService {
304
375
  await removeExpoTokenUtil(this.db, patientId, token);
305
376
  }
306
377
 
307
- async removeExpoTokenByUserRef(userRef: string, token: string): Promise<void> {
378
+ async removeExpoTokenByUserRef(
379
+ userRef: string,
380
+ token: string
381
+ ): Promise<void> {
308
382
  const profile = await this.getPatientProfileByUserRef(userRef);
309
- if (!profile) throw new Error('Patient profile not found');
383
+ if (!profile) throw new Error("Patient profile not found");
310
384
  await this.removeExpoToken(profile.id, token);
311
385
  }
312
386
 
@@ -316,17 +390,19 @@ export class PatientService extends BaseService {
316
390
 
317
391
  async addPointsByUserRef(userRef: string, points: number): Promise<void> {
318
392
  const profile = await this.getPatientProfileByUserRef(userRef);
319
- if (!profile) throw new Error('Patient profile not found');
393
+ if (!profile) throw new Error("Patient profile not found");
320
394
  await this.addPoints(profile.id, points);
321
395
  }
322
396
 
323
397
  private async getCurrentUser(): Promise<any> {
324
398
  if (!this.auth.currentUser) {
325
- throw new Error('No authenticated user');
399
+ throw new Error("No authenticated user");
326
400
  }
327
- const userDoc = await getDoc(doc(this.db, 'users', this.auth.currentUser.uid));
401
+ const userDoc = await getDoc(
402
+ doc(this.db, "users", this.auth.currentUser.uid)
403
+ );
328
404
  if (!userDoc.exists()) {
329
- throw new Error('User not found');
405
+ throw new Error("User not found");
330
406
  }
331
407
  return userDoc.data();
332
408
  }
@@ -388,14 +464,14 @@ export class PatientService extends BaseService {
388
464
  // Metode za ažuriranje profila
389
465
  async updatePatientProfile(
390
466
  patientId: string,
391
- data: Partial<Omit<PatientProfile, 'id' | 'createdAt' | 'updatedAt'>>,
467
+ data: Partial<Omit<PatientProfile, "id" | "createdAt" | "updatedAt">>
392
468
  ): Promise<PatientProfile> {
393
469
  return updatePatientProfileUtil(this.db, patientId, data);
394
470
  }
395
471
 
396
472
  async updatePatientProfileByUserRef(
397
473
  userRef: string,
398
- data: Partial<Omit<PatientProfile, 'id' | 'createdAt' | 'updatedAt'>>,
474
+ data: Partial<Omit<PatientProfile, "id" | "createdAt" | "updatedAt">>
399
475
  ): Promise<PatientProfile> {
400
476
  return updatePatientProfileByUserRefUtil(this.db, userRef, data);
401
477
  }
@@ -410,7 +486,7 @@ export class PatientService extends BaseService {
410
486
  */
411
487
  async searchPatients(
412
488
  params: SearchPatientsParams,
413
- requester: RequesterInfo,
489
+ requester: RequesterInfo
414
490
  ): Promise<PatientProfile[]> {
415
491
  // We can potentially add more service-level logic here in the future,
416
492
  // like fetching additional data or enriching the results.
@@ -419,7 +495,7 @@ export class PatientService extends BaseService {
419
495
  `[PatientService.searchPatients] Initiating search with params:`,
420
496
  params,
421
497
  `by requester:`,
422
- requester,
498
+ requester
423
499
  );
424
500
 
425
501
  // The utility function already handles validation and security checks.
@@ -438,7 +514,54 @@ export class PatientService extends BaseService {
438
514
  limit?: number;
439
515
  startAfter?: string;
440
516
  }): Promise<PatientProfile[]> {
441
- console.log(`[PatientService.getAllPatients] Fetching patients with options:`, options);
517
+ console.log(
518
+ `[PatientService.getAllPatients] Fetching patients with options:`,
519
+ options
520
+ );
442
521
  return getAllPatientsUtil(this.db, options);
443
522
  }
523
+
524
+ /**
525
+ * Gets all patients associated with a specific practitioner.
526
+ *
527
+ * @param {string} practitionerId - ID of the practitioner whose patients to retrieve
528
+ * @param {Object} options - Optional parameters for pagination
529
+ * @param {number} options.limit - Maximum number of profiles to return
530
+ * @param {string} options.startAfter - The ID of the document to start after (for pagination)
531
+ * @returns {Promise<PatientProfile[]>} A promise resolving to an array of patient profiles
532
+ */
533
+ async getPatientsByPractitioner(
534
+ practitionerId: string,
535
+ options?: {
536
+ limit?: number;
537
+ startAfter?: string;
538
+ }
539
+ ): Promise<PatientProfile[]> {
540
+ console.log(
541
+ `[PatientService.getPatientsByPractitioner] Fetching patients for practitioner: ${practitionerId}`
542
+ );
543
+ return getPatientsByPractitionerUtil(this.db, practitionerId, options);
544
+ }
545
+
546
+ /**
547
+ * Gets all patients associated with a specific clinic.
548
+ *
549
+ * @param {string} clinicId - ID of the clinic whose patients to retrieve
550
+ * @param {Object} options - Optional parameters for pagination
551
+ * @param {number} options.limit - Maximum number of profiles to return
552
+ * @param {string} options.startAfter - The ID of the document to start after (for pagination)
553
+ * @returns {Promise<PatientProfile[]>} A promise resolving to an array of patient profiles
554
+ */
555
+ async getPatientsByClinic(
556
+ clinicId: string,
557
+ options?: {
558
+ limit?: number;
559
+ startAfter?: string;
560
+ }
561
+ ): Promise<PatientProfile[]> {
562
+ console.log(
563
+ `[PatientService.getPatientsByClinic] Fetching patients for clinic: ${clinicId}`
564
+ );
565
+ return getPatientsByClinicUtil(this.db, clinicId, options);
566
+ }
444
567
  }
@@ -0,0 +1,80 @@
1
+ import {
2
+ collection,
3
+ query,
4
+ where,
5
+ getDocs,
6
+ Firestore,
7
+ limit,
8
+ startAfter,
9
+ doc,
10
+ getDoc,
11
+ QueryConstraint,
12
+ } from "firebase/firestore";
13
+ import { PatientProfile, PATIENTS_COLLECTION } from "../../../types/patient";
14
+
15
+ /**
16
+ * Retrieves all patients associated with a specific clinic with pagination support.
17
+ *
18
+ * @param {Firestore} db - Firestore instance
19
+ * @param {string} clinicId - ID of the clinic whose patients to retrieve
20
+ * @param {Object} options - Optional parameters for pagination
21
+ * @param {number} options.limit - Maximum number of profiles to return
22
+ * @param {string} options.startAfter - The ID of the document to start after (for pagination)
23
+ * @returns {Promise<PatientProfile[]>} A promise resolving to an array of patient profiles
24
+ */
25
+ export const getPatientsByClinicUtil = async (
26
+ db: Firestore,
27
+ clinicId: string,
28
+ options?: { limit?: number; startAfter?: string }
29
+ ): Promise<PatientProfile[]> => {
30
+ try {
31
+ console.log(
32
+ `[getPatientsByClinicUtil] Fetching patients for clinic ID: ${clinicId} with options:`,
33
+ options
34
+ );
35
+
36
+ const patientsCollection = collection(db, PATIENTS_COLLECTION);
37
+ const constraints: QueryConstraint[] = [
38
+ where("clinicIds", "array-contains", clinicId),
39
+ ];
40
+
41
+ let q = query(patientsCollection, ...constraints);
42
+
43
+ // Apply pagination if needed
44
+ if (options?.limit) {
45
+ q = query(q, limit(options.limit));
46
+ }
47
+
48
+ // If startAfter is provided, get that document and use it for pagination
49
+ if (options?.startAfter) {
50
+ const startAfterDoc = await getDoc(
51
+ doc(db, PATIENTS_COLLECTION, options.startAfter)
52
+ );
53
+ if (startAfterDoc.exists()) {
54
+ q = query(q, startAfter(startAfterDoc));
55
+ }
56
+ }
57
+
58
+ const patientsSnapshot = await getDocs(q);
59
+
60
+ const patients: PatientProfile[] = [];
61
+ patientsSnapshot.forEach((doc) => {
62
+ patients.push(doc.data() as PatientProfile);
63
+ });
64
+
65
+ console.log(
66
+ `[getPatientsByClinicUtil] Found ${patients.length} patients for clinic ID: ${clinicId}`
67
+ );
68
+ return patients;
69
+ } catch (error) {
70
+ console.error(
71
+ `[getPatientsByClinicUtil] Error fetching patients for clinic:`,
72
+ error
73
+ );
74
+ throw new Error(
75
+ `Failed to retrieve patients for clinic: ${
76
+ error instanceof Error ? error.message : String(error)
77
+ }`
78
+ );
79
+ }
80
+ };
@@ -0,0 +1,80 @@
1
+ import {
2
+ collection,
3
+ query,
4
+ where,
5
+ getDocs,
6
+ Firestore,
7
+ limit,
8
+ startAfter,
9
+ doc,
10
+ getDoc,
11
+ QueryConstraint,
12
+ } from "firebase/firestore";
13
+ import { PatientProfile, PATIENTS_COLLECTION } from "../../../types/patient";
14
+
15
+ /**
16
+ * Retrieves all patients associated with a specific practitioner with pagination support.
17
+ *
18
+ * @param {Firestore} db - Firestore instance
19
+ * @param {string} practitionerId - ID of the practitioner whose patients to retrieve
20
+ * @param {Object} options - Optional parameters for pagination
21
+ * @param {number} options.limit - Maximum number of profiles to return
22
+ * @param {string} options.startAfter - The ID of the document to start after (for pagination)
23
+ * @returns {Promise<PatientProfile[]>} A promise resolving to an array of patient profiles
24
+ */
25
+ export const getPatientsByPractitionerUtil = async (
26
+ db: Firestore,
27
+ practitionerId: string,
28
+ options?: { limit?: number; startAfter?: string }
29
+ ): Promise<PatientProfile[]> => {
30
+ try {
31
+ console.log(
32
+ `[getPatientsByPractitionerUtil] Fetching patients for practitioner ID: ${practitionerId} with options:`,
33
+ options
34
+ );
35
+
36
+ const patientsCollection = collection(db, PATIENTS_COLLECTION);
37
+ const constraints: QueryConstraint[] = [
38
+ where("doctorIds", "array-contains", practitionerId),
39
+ ];
40
+
41
+ let q = query(patientsCollection, ...constraints);
42
+
43
+ // Apply pagination if needed
44
+ if (options?.limit) {
45
+ q = query(q, limit(options.limit));
46
+ }
47
+
48
+ // If startAfter is provided, get that document and use it for pagination
49
+ if (options?.startAfter) {
50
+ const startAfterDoc = await getDoc(
51
+ doc(db, PATIENTS_COLLECTION, options.startAfter)
52
+ );
53
+ if (startAfterDoc.exists()) {
54
+ q = query(q, startAfter(startAfterDoc));
55
+ }
56
+ }
57
+
58
+ const patientsSnapshot = await getDocs(q);
59
+
60
+ const patients: PatientProfile[] = [];
61
+ patientsSnapshot.forEach((doc) => {
62
+ patients.push(doc.data() as PatientProfile);
63
+ });
64
+
65
+ console.log(
66
+ `[getPatientsByPractitionerUtil] Found ${patients.length} patients for practitioner ID: ${practitionerId}`
67
+ );
68
+ return patients;
69
+ } catch (error) {
70
+ console.error(
71
+ `[getPatientsByPractitionerUtil] Error fetching patients for practitioner:`,
72
+ error
73
+ );
74
+ throw new Error(
75
+ `Failed to retrieve patients for practitioner: ${
76
+ error instanceof Error ? error.message : String(error)
77
+ }`
78
+ );
79
+ }
80
+ };