@blackcode_sa/metaestetics-api 1.5.29 → 1.5.31

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.
Files changed (30) hide show
  1. package/dist/admin/index.d.mts +126 -1
  2. package/dist/admin/index.d.ts +126 -1
  3. package/dist/admin/index.js +347 -10
  4. package/dist/admin/index.mjs +345 -10
  5. package/dist/index.d.mts +64 -71
  6. package/dist/index.d.ts +64 -71
  7. package/dist/index.js +327 -710
  8. package/dist/index.mjs +363 -750
  9. package/package.json +2 -1
  10. package/src/admin/aggregation/README.md +79 -0
  11. package/src/admin/aggregation/clinic/README.md +52 -0
  12. package/src/admin/aggregation/patient/README.md +27 -0
  13. package/src/admin/aggregation/practitioner/README.md +42 -0
  14. package/src/admin/aggregation/procedure/README.md +43 -0
  15. package/src/admin/index.ts +17 -2
  16. package/src/admin/mailing/README.md +95 -0
  17. package/src/admin/mailing/base.mailing.service.ts +131 -0
  18. package/src/admin/mailing/index.ts +2 -0
  19. package/src/admin/mailing/practitionerInvite/index.ts +1 -0
  20. package/src/admin/mailing/practitionerInvite/practitionerInvite.mailing.ts +256 -0
  21. package/src/admin/mailing/practitionerInvite/templates/invitation.template.ts +101 -0
  22. package/src/services/README.md +106 -0
  23. package/src/services/calendar/utils/appointment.utils.ts +42 -91
  24. package/src/services/clinic/README.md +87 -0
  25. package/src/services/clinic/clinic.service.ts +3 -126
  26. package/src/services/clinic/utils/clinic.utils.ts +2 -2
  27. package/src/services/practitioner/README.md +145 -0
  28. package/src/services/practitioner/practitioner.service.ts +119 -395
  29. package/src/services/procedure/README.md +88 -0
  30. package/src/services/procedure/procedure.service.ts +332 -369
package/dist/index.js CHANGED
@@ -3564,86 +3564,21 @@ var PractitionerService = class extends BaseService {
3564
3564
  }
3565
3565
  getClinicService() {
3566
3566
  if (!this.clinicService) {
3567
- throw new Error("ClinicService nije inicijalizovan");
3567
+ throw new Error("Clinic service not initialized!");
3568
3568
  }
3569
3569
  return this.clinicService;
3570
3570
  }
3571
- /**
3572
- * Postavlja referencu na ClinicService nakon inicijalizacije
3573
- */
3574
3571
  setClinicService(clinicService) {
3575
3572
  this.clinicService = clinicService;
3576
3573
  }
3577
3574
  /**
3578
- * Aggregates clinic information for a practitioner
3579
- * @param clinicIds Array of clinic IDs the practitioner works at
3580
- * @returns Array of ClinicInfo objects
3581
- */
3582
- async aggregateClinicInfo(clinicIds) {
3583
- const clinicsInfo = [];
3584
- for (const clinicId of clinicIds) {
3585
- const clinic = await this.getClinicService().getClinic(clinicId);
3586
- if (!clinic) continue;
3587
- clinicsInfo.push({
3588
- id: clinic.id,
3589
- featuredPhoto: clinic.featuredPhotos && clinic.featuredPhotos.length > 0 ? clinic.featuredPhotos[0] : clinic.coverPhoto || "",
3590
- name: clinic.name,
3591
- description: clinic.description || "",
3592
- location: clinic.location,
3593
- contactInfo: clinic.contactInfo
3594
- });
3595
- }
3596
- return clinicsInfo;
3597
- }
3598
- /**
3599
- * @deprecated Aggregation of procedure info is now handled by ProcedureService.
3600
- */
3601
- async aggregateProcedureInfo(clinicIds, practitionerId) {
3602
- console.warn("PractitionerService.aggregateProcedureInfo is deprecated.");
3603
- return [];
3604
- }
3605
- /**
3606
- * Updates aggregated data (clinics and procedures) for a practitioner
3607
- * @param practitionerId ID of the practitioner to update
3608
- * @returns Updated practitioner
3609
- */
3610
- async updateAggregatedData(practitionerId) {
3611
- const practitioner = await this.getPractitioner(practitionerId);
3612
- if (!practitioner) {
3613
- return null;
3614
- }
3615
- const clinicsInfo = await this.aggregateClinicInfo(practitioner.clinics);
3616
- const proceduresInfo = await this.aggregateProcedureInfo(
3617
- practitioner.clinics,
3618
- practitionerId
3619
- );
3620
- const updatedPractitioner = await this.updatePractitioner(practitionerId, {
3621
- clinicsInfo,
3622
- proceduresInfo
3623
- });
3624
- return updatedPractitioner;
3625
- }
3626
- /**
3627
- * Kreira novog zdravstvenog radnika
3575
+ * Creates a new practitioner
3628
3576
  */
3629
3577
  async createPractitioner(data) {
3630
3578
  try {
3631
- const validatedData = createPractitionerSchema.parse(data);
3632
- const existingPractitioner = await this.getPractitionerByUserRef(
3633
- validatedData.userRef
3634
- );
3635
- if (existingPractitioner) {
3636
- throw new Error("User already has a practitioner profile");
3637
- }
3638
- if (validatedData.clinics) {
3639
- for (const clinicId of validatedData.clinics) {
3640
- const clinic = await this.getClinicService().getClinic(clinicId);
3641
- if (!clinic) {
3642
- throw new Error(`Clinic ${clinicId} not found`);
3643
- }
3644
- }
3645
- }
3646
- const defaultReviewInfo = {
3579
+ const validData = createPractitionerSchema.parse(data);
3580
+ const practitionerId = this.generateId();
3581
+ const reviewInfo = {
3647
3582
  totalReviews: 0,
3648
3583
  averageRating: 0,
3649
3584
  knowledgeAndExpertise: 0,
@@ -3653,50 +3588,46 @@ var PractitionerService = class extends BaseService {
3653
3588
  trustworthiness: 0,
3654
3589
  recommendationPercentage: 0
3655
3590
  };
3656
- const practitionerId = this.generateId();
3657
- let clinicsInfo = validatedData.clinicsInfo || [];
3658
- if (clinicsInfo.length === 0 && validatedData.clinics && validatedData.clinics.length > 0) {
3659
- clinicsInfo = await this.aggregateClinicInfo(validatedData.clinics);
3660
- }
3661
- const proceduresInfo = [];
3662
- const practitionerData = {
3591
+ const practitioner = {
3663
3592
  id: practitionerId,
3664
- userRef: validatedData.userRef,
3665
- basicInfo: validatedData.basicInfo,
3666
- certification: validatedData.certification,
3667
- clinics: validatedData.clinics || [],
3668
- clinicWorkingHours: validatedData.clinicWorkingHours || [],
3669
- clinicsInfo,
3593
+ userRef: validData.userRef,
3594
+ basicInfo: validData.basicInfo,
3595
+ certification: validData.certification,
3596
+ clinics: validData.clinics || [],
3597
+ clinicWorkingHours: validData.clinicWorkingHours || [],
3598
+ clinicsInfo: [],
3670
3599
  procedures: [],
3671
- proceduresInfo,
3672
- reviewInfo: defaultReviewInfo,
3673
- isActive: validatedData.isActive,
3674
- isVerified: validatedData.isVerified,
3675
- status: validatedData.status || "active" /* ACTIVE */,
3600
+ proceduresInfo: [],
3601
+ reviewInfo,
3602
+ isActive: validData.isActive !== void 0 ? validData.isActive : true,
3603
+ isVerified: validData.isVerified !== void 0 ? validData.isVerified : false,
3604
+ status: validData.status || "active" /* ACTIVE */,
3676
3605
  createdAt: (0, import_firestore13.serverTimestamp)(),
3677
3606
  updatedAt: (0, import_firestore13.serverTimestamp)()
3678
3607
  };
3679
3608
  practitionerSchema.parse({
3680
- ...practitionerData,
3609
+ ...practitioner,
3681
3610
  createdAt: import_firestore13.Timestamp.now(),
3682
3611
  updatedAt: import_firestore13.Timestamp.now()
3683
3612
  });
3684
- await (0, import_firestore13.setDoc)(
3685
- (0, import_firestore13.doc)(this.db, PRACTITIONERS_COLLECTION, practitionerData.id),
3686
- practitionerData
3613
+ const practitionerRef = (0, import_firestore13.doc)(
3614
+ this.db,
3615
+ PRACTITIONERS_COLLECTION,
3616
+ practitionerId
3687
3617
  );
3688
- let savedPractitioner = await this.getPractitioner(practitionerData.id);
3689
- if (!savedPractitioner) {
3690
- throw new Error("Failed to create practitioner profile");
3691
- }
3692
- if (proceduresInfo.length === 0 && validatedData.clinics && validatedData.clinics.length > 0) {
3693
- savedPractitioner = await this.updateAggregatedData(savedPractitioner.id) || savedPractitioner;
3618
+ await (0, import_firestore13.setDoc)(practitionerRef, practitioner);
3619
+ const createdPractitioner = await this.getPractitioner(practitionerId);
3620
+ if (!createdPractitioner) {
3621
+ throw new Error(
3622
+ `Failed to retrieve created practitioner ${practitionerId}`
3623
+ );
3694
3624
  }
3695
- return savedPractitioner;
3625
+ return createdPractitioner;
3696
3626
  } catch (error) {
3697
3627
  if (error instanceof import_zod12.z.ZodError) {
3698
- throw new Error("Invalid practitioner data: " + error.message);
3628
+ throw new Error(`Invalid practitioner data: ${error.message}`);
3699
3629
  }
3630
+ console.error("Error creating practitioner:", error);
3700
3631
  throw error;
3701
3632
  }
3702
3633
  }
@@ -3737,10 +3668,7 @@ var PractitionerService = class extends BaseService {
3737
3668
  recommendationPercentage: 0
3738
3669
  };
3739
3670
  const practitionerId = this.generateId();
3740
- let clinicsInfo = validatedData.clinicsInfo || [];
3741
- if (clinicsInfo.length === 0 && clinics.length > 0) {
3742
- clinicsInfo = await this.aggregateClinicInfo(clinics);
3743
- }
3671
+ const clinicsInfo = validatedData.clinicsInfo || [];
3744
3672
  const proceduresInfo = [];
3745
3673
  const practitionerData = {
3746
3674
  id: practitionerId,
@@ -3977,113 +3905,100 @@ var PractitionerService = class extends BaseService {
3977
3905
  return querySnapshot.docs.map((doc28) => doc28.data());
3978
3906
  }
3979
3907
  /**
3980
- * Ažurira profil zdravstvenog radnika
3908
+ * Updates a practitioner
3981
3909
  */
3982
3910
  async updatePractitioner(practitionerId, data) {
3983
- const practitionerRef = (0, import_firestore13.doc)(
3984
- this.db,
3985
- PRACTITIONERS_COLLECTION,
3986
- practitionerId
3987
- );
3988
- const practitionerDoc = await (0, import_firestore13.getDoc)(practitionerRef);
3989
- if (!practitionerDoc.exists()) {
3990
- throw new Error("Practitioner not found");
3991
- }
3992
3911
  try {
3993
- const currentPractitioner = practitionerDoc.data();
3994
- if (data.clinics) {
3995
- for (const clinicId of data.clinics) {
3996
- const clinic = await this.getClinicService().getClinic(clinicId);
3997
- if (!clinic) {
3998
- throw new Error(`Clinic ${clinicId} not found`);
3999
- }
4000
- }
4001
- if (!data.clinicsInfo) {
4002
- data.clinicsInfo = await this.aggregateClinicInfo(data.clinics);
4003
- }
4004
- if (!data.proceduresInfo) {
4005
- data.proceduresInfo = await this.aggregateProcedureInfo(
4006
- data.clinics,
4007
- practitionerId
4008
- );
4009
- }
3912
+ const validData = data;
3913
+ const practitionerRef = (0, import_firestore13.doc)(
3914
+ this.db,
3915
+ PRACTITIONERS_COLLECTION,
3916
+ practitionerId
3917
+ );
3918
+ const practitionerDoc = await (0, import_firestore13.getDoc)(practitionerRef);
3919
+ if (!practitionerDoc.exists()) {
3920
+ throw new Error(`Practitioner ${practitionerId} not found`);
4010
3921
  }
3922
+ const currentPractitioner = practitionerDoc.data();
4011
3923
  const updateData = {
4012
- ...data,
3924
+ ...validData,
4013
3925
  updatedAt: (0, import_firestore13.serverTimestamp)()
4014
3926
  };
4015
- practitionerSchema.parse({
4016
- ...currentPractitioner,
4017
- ...data,
4018
- updatedAt: import_firestore13.Timestamp.now()
4019
- });
4020
3927
  await (0, import_firestore13.updateDoc)(practitionerRef, updateData);
4021
3928
  const updatedPractitioner = await this.getPractitioner(practitionerId);
4022
3929
  if (!updatedPractitioner) {
4023
- throw new Error("Failed to retrieve updated practitioner profile");
3930
+ throw new Error(
3931
+ `Failed to retrieve updated practitioner ${practitionerId}`
3932
+ );
4024
3933
  }
4025
3934
  return updatedPractitioner;
4026
3935
  } catch (error) {
4027
3936
  if (error instanceof import_zod12.z.ZodError) {
4028
- throw new Error("Invalid practitioner data: " + error.message);
3937
+ throw new Error(`Invalid practitioner update data: ${error.message}`);
4029
3938
  }
3939
+ console.error(`Error updating practitioner ${practitionerId}:`, error);
4030
3940
  throw error;
4031
3941
  }
4032
3942
  }
4033
3943
  /**
4034
- * Dodaje kliniku zdravstvenom radniku
3944
+ * Adds a clinic to a practitioner
4035
3945
  */
4036
3946
  async addClinic(practitionerId, clinicId) {
4037
- const practitioner = await this.getPractitioner(practitionerId);
4038
- if (!practitioner) {
4039
- throw new Error("Practitioner not found");
4040
- }
4041
- const clinic = await this.getClinicService().getClinic(clinicId);
4042
- if (!clinic) {
4043
- throw new Error("Clinic not found");
4044
- }
4045
- if (practitioner.clinics.includes(clinicId)) {
4046
- throw new Error("Practitioner is already associated with this clinic");
3947
+ var _a;
3948
+ try {
3949
+ const practitionerRef = (0, import_firestore13.doc)(
3950
+ this.db,
3951
+ PRACTITIONERS_COLLECTION,
3952
+ practitionerId
3953
+ );
3954
+ const practitionerDoc = await (0, import_firestore13.getDoc)(practitionerRef);
3955
+ if (!practitionerDoc.exists()) {
3956
+ throw new Error(`Practitioner ${practitionerId} not found`);
3957
+ }
3958
+ const practitioner = practitionerDoc.data();
3959
+ if ((_a = practitioner.clinics) == null ? void 0 : _a.includes(clinicId)) {
3960
+ console.log(
3961
+ `Clinic ${clinicId} already added to practitioner ${practitionerId}`
3962
+ );
3963
+ return;
3964
+ }
3965
+ await (0, import_firestore13.updateDoc)(practitionerRef, {
3966
+ clinics: (0, import_firestore13.arrayUnion)(clinicId),
3967
+ updatedAt: (0, import_firestore13.serverTimestamp)()
3968
+ });
3969
+ } catch (error) {
3970
+ console.error(
3971
+ `Error adding clinic ${clinicId} to practitioner ${practitionerId}:`,
3972
+ error
3973
+ );
3974
+ throw error;
4047
3975
  }
4048
- const updatedClinics = [...practitioner.clinics, clinicId];
4049
- const clinicInfo = {
4050
- id: clinic.id,
4051
- name: clinic.name,
4052
- description: clinic.description || "",
4053
- featuredPhoto: clinic.featuredPhotos && clinic.featuredPhotos.length > 0 ? clinic.featuredPhotos[0] : clinic.coverPhoto || "",
4054
- location: clinic.location,
4055
- contactInfo: clinic.contactInfo
4056
- };
4057
- const updatedClinicsInfo = [...practitioner.clinicsInfo, clinicInfo];
4058
- await this.updatePractitioner(practitionerId, {
4059
- clinics: updatedClinics,
4060
- clinicsInfo: updatedClinicsInfo
4061
- });
4062
- await this.updateAggregatedData(practitionerId);
4063
3976
  }
4064
3977
  /**
4065
- * Uklanja kliniku iz liste klinika zdravstvenog radnika
3978
+ * Removes a clinic from a practitioner
4066
3979
  */
4067
3980
  async removeClinic(practitionerId, clinicId) {
4068
- const practitioner = await this.getPractitioner(practitionerId);
4069
- if (!practitioner) {
4070
- throw new Error("Practitioner not found");
4071
- }
4072
- if (!practitioner.clinics.includes(clinicId)) {
4073
- throw new Error("Practitioner is not associated with this clinic");
3981
+ try {
3982
+ const practitionerRef = (0, import_firestore13.doc)(
3983
+ this.db,
3984
+ PRACTITIONERS_COLLECTION,
3985
+ practitionerId
3986
+ );
3987
+ const practitionerDoc = await (0, import_firestore13.getDoc)(practitionerRef);
3988
+ if (!practitionerDoc.exists()) {
3989
+ throw new Error(`Practitioner ${practitionerId} not found`);
3990
+ }
3991
+ await (0, import_firestore13.updateDoc)(practitionerRef, {
3992
+ clinics: (0, import_firestore13.arrayRemove)(clinicId),
3993
+ updatedAt: (0, import_firestore13.serverTimestamp)()
3994
+ });
3995
+ } catch (error) {
3996
+ console.error(
3997
+ `Error removing clinic ${clinicId} from practitioner ${practitionerId}:`,
3998
+ error
3999
+ );
4000
+ throw error;
4074
4001
  }
4075
- const updatedClinics = practitioner.clinics.filter((id) => id !== clinicId);
4076
- const updatedClinicsInfo = practitioner.clinicsInfo.filter(
4077
- (clinic) => clinic.id !== clinicId
4078
- );
4079
- const updatedProceduresInfo = practitioner.proceduresInfo.filter(
4080
- (procedure) => procedure.clinicId !== clinicId
4081
- );
4082
- await this.updatePractitioner(practitionerId, {
4083
- clinics: updatedClinics,
4084
- clinicsInfo: updatedClinicsInfo,
4085
- proceduresInfo: updatedProceduresInfo
4086
- });
4087
4002
  }
4088
4003
  /**
4089
4004
  * Deaktivira profil zdravstvenog radnika
@@ -4321,112 +4236,6 @@ var PractitionerService = class extends BaseService {
4321
4236
  throw error;
4322
4237
  }
4323
4238
  }
4324
- // --- Helper Functions ---
4325
- /**
4326
- * Aggregates essential clinic information for embedding in Practitioner.
4327
- * @param clinicIds Array of clinic IDs the practitioner works at
4328
- * @returns Array of ClinicInfo objects
4329
- */
4330
- async _aggregateClinicInfoForPractitioner(clinicIds) {
4331
- const clinicsInfo = [];
4332
- const clinicService = this.getClinicService();
4333
- for (const clinicId of clinicIds) {
4334
- try {
4335
- const clinic = await clinicService.getClinic(clinicId);
4336
- if (!clinic) {
4337
- console.warn(
4338
- `Clinic ${clinicId} not found during practitioner aggregation.`
4339
- );
4340
- continue;
4341
- }
4342
- clinicsInfo.push({
4343
- id: clinic.id,
4344
- featuredPhoto: clinic.featuredPhotos && clinic.featuredPhotos.length > 0 ? clinic.featuredPhotos[0] : clinic.coverPhoto || "",
4345
- name: clinic.name,
4346
- description: clinic.description || "",
4347
- location: clinic.location,
4348
- contactInfo: clinic.contactInfo
4349
- });
4350
- } catch (error) {
4351
- console.error(
4352
- `Error fetching clinic ${clinicId} for practitioner aggregation:`,
4353
- error
4354
- );
4355
- }
4356
- }
4357
- return clinicsInfo;
4358
- }
4359
- /**
4360
- * Creates an aggregated DoctorInfo object from Practitioner data.
4361
- * @param practitioner The practitioner object
4362
- * @returns DoctorInfo object
4363
- */
4364
- _createDoctorInfoForClinic(practitioner) {
4365
- var _a;
4366
- return {
4367
- id: practitioner.id,
4368
- name: `${practitioner.basicInfo.firstName} ${practitioner.basicInfo.lastName}`,
4369
- description: practitioner.basicInfo.bio || "",
4370
- photo: practitioner.basicInfo.profileImageUrl || "",
4371
- rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
4372
- services: practitioner.procedures || []
4373
- // List of procedure IDs
4374
- };
4375
- }
4376
- /**
4377
- * Updates the DoctorInfo within the doctorsInfo array for multiple clinics.
4378
- * @param clinicIds IDs of clinics to update
4379
- * @param doctorInfo The updated DoctorInfo object
4380
- */
4381
- async _updateDoctorInfoInClinics(clinicIds, doctorInfo) {
4382
- const batch = (0, import_firestore13.writeBatch)(this.db);
4383
- const practitionerId = doctorInfo.id;
4384
- for (const clinicId of clinicIds) {
4385
- const clinicRef = (0, import_firestore13.doc)(this.db, CLINICS_COLLECTION, clinicId);
4386
- batch.update(clinicRef, {
4387
- doctorsInfo: (0, import_firestore13.arrayRemove)(...[{ id: practitionerId }]),
4388
- updatedAt: (0, import_firestore13.serverTimestamp)()
4389
- });
4390
- batch.update(clinicRef, {
4391
- doctorsInfo: (0, import_firestore13.arrayUnion)(doctorInfo),
4392
- updatedAt: (0, import_firestore13.serverTimestamp)()
4393
- });
4394
- }
4395
- try {
4396
- await batch.commit();
4397
- } catch (error) {
4398
- console.error(
4399
- `Error updating doctor info in clinics for practitioner ${practitionerId}:`,
4400
- error
4401
- );
4402
- }
4403
- }
4404
- /**
4405
- * Removes DoctorInfo from the doctorsInfo array for multiple clinics.
4406
- * @param clinicIds IDs of clinics to update
4407
- * @param practitionerId ID of the practitioner whose info should be removed
4408
- */
4409
- async _removeDoctorInfoFromClinics(clinicIds, practitionerId) {
4410
- const batch = (0, import_firestore13.writeBatch)(this.db);
4411
- for (const clinicId of clinicIds) {
4412
- const clinicRef = (0, import_firestore13.doc)(this.db, CLINICS_COLLECTION, clinicId);
4413
- batch.update(clinicRef, {
4414
- doctors: (0, import_firestore13.arrayRemove)(practitionerId),
4415
- // Also remove from simple ID list
4416
- doctorsInfo: (0, import_firestore13.arrayRemove)(...[{ id: practitionerId }]),
4417
- // Remove by ID matcher
4418
- updatedAt: (0, import_firestore13.serverTimestamp)()
4419
- });
4420
- }
4421
- try {
4422
- await batch.commit();
4423
- } catch (error) {
4424
- console.error(
4425
- `Error removing doctor info from clinics for practitioner ${practitionerId}:`,
4426
- error
4427
- );
4428
- }
4429
- }
4430
4239
  };
4431
4240
 
4432
4241
  // src/services/user.service.ts
@@ -5590,15 +5399,14 @@ async function getAllClinics(db, pagination, lastDoc) {
5590
5399
  const clinicsCollection = (0, import_firestore16.collection)(db, CLINICS_COLLECTION);
5591
5400
  let clinicsQuery = (0, import_firestore16.query)(clinicsCollection);
5592
5401
  if (pagination && pagination > 0) {
5593
- const { limit: limit6, startAfter: startAfter6 } = require("firebase/firestore");
5594
5402
  if (lastDoc) {
5595
5403
  clinicsQuery = (0, import_firestore16.query)(
5596
5404
  clinicsCollection,
5597
- startAfter6(lastDoc),
5598
- limit6(pagination)
5405
+ (0, import_firestore16.startAfter)(lastDoc),
5406
+ (0, import_firestore16.limit)(pagination)
5599
5407
  );
5600
5408
  } else {
5601
- clinicsQuery = (0, import_firestore16.query)(clinicsCollection, limit6(pagination));
5409
+ clinicsQuery = (0, import_firestore16.query)(clinicsCollection, (0, import_firestore16.limit)(pagination));
5602
5410
  }
5603
5411
  }
5604
5412
  const clinicsSnapshot = await (0, import_firestore16.getDocs)(clinicsQuery);
@@ -5933,59 +5741,8 @@ var ClinicService = class extends BaseService {
5933
5741
  this.clinicAdminService = clinicAdminService;
5934
5742
  this.clinicGroupService = clinicGroupService;
5935
5743
  }
5936
- // --- Helper Functions ---
5937
- /**
5938
- * Creates an aggregated ClinicInfo object from Clinic data.
5939
- * @param clinic The clinic object
5940
- * @returns ClinicInfo object
5941
- */
5942
- _createClinicInfoForAggregation(clinic) {
5943
- return {
5944
- id: clinic.id,
5945
- featuredPhoto: clinic.featuredPhotos && clinic.featuredPhotos.length > 0 ? clinic.featuredPhotos[0] : clinic.coverPhoto || "",
5946
- name: clinic.name,
5947
- description: clinic.description || "",
5948
- location: clinic.location,
5949
- contactInfo: clinic.contactInfo
5950
- };
5951
- }
5952
- /**
5953
- * Updates the ClinicInfo within the clinicsInfo array for multiple practitioners.
5954
- * @param practitionerIds IDs of practitioners to update
5955
- * @param clinicInfo The updated ClinicInfo object
5956
- */
5957
- async _updateClinicInfoInPractitioners(practitionerIds, clinicInfo) {
5958
- const batch = (0, import_firestore19.writeBatch)(this.db);
5959
- const clinicId = clinicInfo.id;
5960
- for (const practitionerId of practitionerIds) {
5961
- const practitionerRef = (0, import_firestore19.doc)(
5962
- this.db,
5963
- PRACTITIONERS_COLLECTION,
5964
- practitionerId
5965
- );
5966
- batch.update(practitionerRef, {
5967
- clinicsInfo: (0, import_firestore19.arrayRemove)(...[{ id: clinicId }]),
5968
- updatedAt: (0, import_firestore19.serverTimestamp)()
5969
- });
5970
- batch.update(practitionerRef, {
5971
- clinicsInfo: (0, import_firestore19.arrayUnion)(clinicInfo),
5972
- updatedAt: (0, import_firestore19.serverTimestamp)()
5973
- });
5974
- }
5975
- try {
5976
- await batch.commit();
5977
- } catch (error) {
5978
- console.error(
5979
- `Error updating clinic info in practitioners for clinic ${clinicId}:`,
5980
- error
5981
- );
5982
- }
5983
- }
5984
- // --- Core Service Methods (Updated) ---
5985
5744
  /**
5986
5745
  * Creates a new clinic.
5987
- * Initializes empty doctorsInfo and proceduresInfo.
5988
- * Aggregation into Clinic happens via PractitionerService and ProcedureService.
5989
5746
  */
5990
5747
  async createClinic(data, creatorAdminId) {
5991
5748
  try {
@@ -6042,20 +5799,6 @@ var ClinicService = class extends BaseService {
6042
5799
  const batch = (0, import_firestore19.writeBatch)(this.db);
6043
5800
  const clinicRef = (0, import_firestore19.doc)(this.db, CLINICS_COLLECTION, clinicId);
6044
5801
  batch.set(clinicRef, clinicData);
6045
- const groupRef = (0, import_firestore19.doc)(
6046
- this.db,
6047
- CLINIC_GROUPS_COLLECTION,
6048
- validatedData.clinicGroupId
6049
- );
6050
- const newClinicInfoForGroup = this._createClinicInfoForAggregation({
6051
- ...clinicData,
6052
- id: clinicId
6053
- });
6054
- batch.update(groupRef, {
6055
- clinics: (0, import_firestore19.arrayUnion)(clinicId),
6056
- clinicsInfo: (0, import_firestore19.arrayUnion)(newClinicInfoForGroup),
6057
- updatedAt: (0, import_firestore19.serverTimestamp)()
6058
- });
6059
5802
  const adminRef = (0, import_firestore19.doc)(this.db, CLINIC_ADMINS_COLLECTION, creatorAdminId);
6060
5803
  batch.update(adminRef, {
6061
5804
  clinicsManaged: (0, import_firestore19.arrayUnion)(clinicId),
@@ -6074,7 +5817,7 @@ var ClinicService = class extends BaseService {
6074
5817
  }
6075
5818
  }
6076
5819
  /**
6077
- * Updates a clinic and propagates changes (ClinicInfo) to associated practitioners.
5820
+ * Updates a clinic.
6078
5821
  */
6079
5822
  async updateClinic(clinicId, data, adminId) {
6080
5823
  const clinicRef = (0, import_firestore19.doc)(this.db, CLINICS_COLLECTION, clinicId);
@@ -6109,32 +5852,7 @@ var ClinicService = class extends BaseService {
6109
5852
  ...updatePayload,
6110
5853
  updatedAt: (0, import_firestore19.serverTimestamp)()
6111
5854
  };
6112
- const batch = (0, import_firestore19.writeBatch)(this.db);
6113
- batch.update(clinicRef, updateDataForFirestore);
6114
- const groupRef = (0, import_firestore19.doc)(
6115
- this.db,
6116
- CLINIC_GROUPS_COLLECTION,
6117
- currentClinic.clinicGroupId
6118
- );
6119
- const updatedClinicInfoForGroup = this._createClinicInfoForAggregation(
6120
- finalStateForValidation
6121
- );
6122
- batch.update(groupRef, {
6123
- clinicsInfo: (0, import_firestore19.arrayRemove)(...[{ id: clinicId }]),
6124
- updatedAt: (0, import_firestore19.serverTimestamp)()
6125
- });
6126
- batch.update(groupRef, {
6127
- clinicsInfo: (0, import_firestore19.arrayUnion)(updatedClinicInfoForGroup),
6128
- updatedAt: (0, import_firestore19.serverTimestamp)()
6129
- });
6130
- const practitionerIds = currentClinic.doctors || [];
6131
- if (practitionerIds.length > 0) {
6132
- await this._updateClinicInfoInPractitioners(
6133
- practitionerIds,
6134
- updatedClinicInfoForGroup
6135
- );
6136
- }
6137
- await batch.commit();
5855
+ await (0, import_firestore19.updateDoc)(clinicRef, updateDataForFirestore);
6138
5856
  const updatedClinic = await this.getClinic(clinicId);
6139
5857
  if (!updatedClinic) throw new Error("Failed to retrieve updated clinic");
6140
5858
  return updatedClinic;
@@ -6150,7 +5868,6 @@ var ClinicService = class extends BaseService {
6150
5868
  }
6151
5869
  /**
6152
5870
  * Deactivates a clinic.
6153
- * Note: Does not currently remove ClinicInfo from practitioners (might be desired).
6154
5871
  */
6155
5872
  async deactivateClinic(clinicId, adminId) {
6156
5873
  const clinicRef = (0, import_firestore19.doc)(this.db, CLINICS_COLLECTION, clinicId);
@@ -6159,10 +5876,6 @@ var ClinicService = class extends BaseService {
6159
5876
  updatedAt: (0, import_firestore19.serverTimestamp)()
6160
5877
  });
6161
5878
  }
6162
- // --- Other Methods ---
6163
- // (getClinic, getClinicsByGroup, findClinicsInRadius, addTags, removeTags, getClinicsByAdmin, etc.)
6164
- // Review these methods to ensure they don't rely on outdated aggregation logic (e.g., filtering ServiceInfo)
6165
- // and update them to use proceduresInfo if necessary for filtering.
6166
5879
  /**
6167
5880
  * Dohvata kliniku po ID-u
6168
5881
  */
@@ -6177,12 +5890,8 @@ var ClinicService = class extends BaseService {
6177
5890
  }
6178
5891
  /**
6179
5892
  * Pretražuje klinike u određenom radijusu
6180
- * REVIEW: SearchUtils.findClinicsInRadius might need updating for filters.
6181
5893
  */
6182
5894
  async findClinicsInRadius(center, radiusInKm, filters) {
6183
- console.warn(
6184
- "SearchUtils.findClinicsInRadius filter logic might need updating for proceduresInfo."
6185
- );
6186
5895
  return findClinicsInRadius(
6187
5896
  this.db,
6188
5897
  center,
@@ -7208,6 +6917,7 @@ var procedureSchema = createProcedureSchema.extend({
7208
6917
  });
7209
6918
 
7210
6919
  // src/services/procedure/procedure.service.ts
6920
+ var import_geofire_common8 = require("geofire-common");
7211
6921
  var ProcedureService = class extends BaseService {
7212
6922
  constructor(db, auth, app, categoryService, subcategoryService, technologyService, productService) {
7213
6923
  super(db, auth, app);
@@ -7216,108 +6926,8 @@ var ProcedureService = class extends BaseService {
7216
6926
  this.technologyService = technologyService;
7217
6927
  this.productService = productService;
7218
6928
  }
7219
- // Helper function to create ProcedureSummaryInfo
7220
- _createProcedureSummaryInfo(procedure) {
7221
- var _a, _b, _c, _d, _e;
7222
- const categoryName = ((_a = procedure.category) == null ? void 0 : _a.name) || "N/A";
7223
- const subcategoryName = ((_b = procedure.subcategory) == null ? void 0 : _b.name) || "N/A";
7224
- const technologyName = ((_c = procedure.technology) == null ? void 0 : _c.name) || "N/A";
7225
- const clinicName = ((_d = procedure.clinicInfo) == null ? void 0 : _d.name) || "N/A";
7226
- const practitionerName = ((_e = procedure.doctorInfo) == null ? void 0 : _e.name) || "N/A";
7227
- return {
7228
- id: procedure.id,
7229
- name: procedure.name,
7230
- description: procedure.description || "",
7231
- photo: "",
7232
- // No photo source identified yet
7233
- family: procedure.family,
7234
- categoryName,
7235
- subcategoryName,
7236
- technologyName,
7237
- price: procedure.price,
7238
- pricingMeasure: procedure.pricingMeasure,
7239
- currency: procedure.currency,
7240
- duration: procedure.duration,
7241
- clinicId: procedure.clinicBranchId,
7242
- clinicName,
7243
- practitionerId: procedure.practitionerId,
7244
- practitionerName
7245
- };
7246
- }
7247
- // Helper to update practitioner's procedures
7248
- async _updatePractitionerProcedures(practitionerId, procedureSummary, procedureIdToRemove) {
7249
- const practitionerRef = (0, import_firestore22.doc)(
7250
- this.db,
7251
- PRACTITIONERS_COLLECTION,
7252
- practitionerId
7253
- );
7254
- const updateData = {};
7255
- if (procedureSummary) {
7256
- updateData["procedures"] = (0, import_firestore22.arrayUnion)(procedureSummary.id);
7257
- updateData["proceduresInfo"] = (0, import_firestore22.arrayRemove)(
7258
- ...[
7259
- // Need to spread the arrayRemove arguments
7260
- // Create a 'matcher' object with only the ID for removal
7261
- { id: procedureSummary.id }
7262
- ]
7263
- );
7264
- } else if (procedureIdToRemove) {
7265
- updateData["procedures"] = (0, import_firestore22.arrayRemove)(procedureIdToRemove);
7266
- updateData["proceduresInfo"] = (0, import_firestore22.arrayRemove)(
7267
- ...[{ id: procedureIdToRemove }]
7268
- // Use matcher for removal
7269
- );
7270
- } else {
7271
- return;
7272
- }
7273
- updateData["updatedAt"] = (0, import_firestore22.serverTimestamp)();
7274
- const batch = (0, import_firestore22.writeBatch)(this.db);
7275
- batch.update(practitionerRef, updateData);
7276
- if (procedureSummary) {
7277
- batch.update(practitionerRef, {
7278
- proceduresInfo: (0, import_firestore22.arrayUnion)(procedureSummary)
7279
- });
7280
- }
7281
- await batch.commit();
7282
- }
7283
- // Helper to update clinic's procedures
7284
- async _updateClinicProcedures(clinicId, procedureSummary, procedureIdToRemove) {
7285
- const clinicRef = (0, import_firestore22.doc)(this.db, CLINICS_COLLECTION, clinicId);
7286
- const clinicSnap = await (0, import_firestore22.getDoc)(clinicRef);
7287
- if (!clinicSnap.exists()) {
7288
- console.warn(
7289
- `Clinic ${clinicId} not found, skipping procedure aggregation update.`
7290
- );
7291
- return;
7292
- }
7293
- const updateData = {};
7294
- if (procedureSummary) {
7295
- updateData["services"] = (0, import_firestore22.arrayUnion)(procedureSummary.id);
7296
- updateData["proceduresInfo"] = (0, import_firestore22.arrayRemove)(
7297
- ...[{ id: procedureSummary.id }]
7298
- // Use matcher for removal
7299
- );
7300
- } else if (procedureIdToRemove) {
7301
- updateData["services"] = (0, import_firestore22.arrayRemove)(procedureIdToRemove);
7302
- updateData["proceduresInfo"] = (0, import_firestore22.arrayRemove)(
7303
- ...[{ id: procedureIdToRemove }]
7304
- // Use matcher for removal
7305
- );
7306
- } else {
7307
- return;
7308
- }
7309
- updateData["updatedAt"] = (0, import_firestore22.serverTimestamp)();
7310
- const batch = (0, import_firestore22.writeBatch)(this.db);
7311
- batch.update(clinicRef, updateData);
7312
- if (procedureSummary) {
7313
- batch.update(clinicRef, {
7314
- proceduresInfo: (0, import_firestore22.arrayUnion)(procedureSummary)
7315
- });
7316
- }
7317
- await batch.commit();
7318
- }
7319
6929
  /**
7320
- * Creates a new procedure and updates related practitioner/clinic aggregates
6930
+ * Creates a new procedure
7321
6931
  * @param data - The data for creating a new procedure
7322
6932
  * @returns The created procedure
7323
6933
  */
@@ -7377,9 +6987,7 @@ var ProcedureService = class extends BaseService {
7377
6987
  description: practitioner.basicInfo.bio || "",
7378
6988
  photo: practitioner.basicInfo.profileImageUrl || "",
7379
6989
  rating: ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0,
7380
- // Example rating source
7381
6990
  services: practitioner.procedures || []
7382
- // Link services to practitioner's procedures
7383
6991
  };
7384
6992
  const procedureId = this.generateId();
7385
6993
  const newProcedure = {
@@ -7414,37 +7022,12 @@ var ProcedureService = class extends BaseService {
7414
7022
  isActive: true
7415
7023
  // Default to active
7416
7024
  };
7417
- const batch = (0, import_firestore22.writeBatch)(this.db);
7418
7025
  const procedureRef = (0, import_firestore22.doc)(this.db, PROCEDURES_COLLECTION, procedureId);
7419
- batch.set(procedureRef, {
7026
+ await (0, import_firestore22.setDoc)(procedureRef, {
7420
7027
  ...newProcedure,
7421
7028
  createdAt: (0, import_firestore22.serverTimestamp)(),
7422
7029
  updatedAt: (0, import_firestore22.serverTimestamp)()
7423
7030
  });
7424
- const procedureSummary = this._createProcedureSummaryInfo({
7425
- ...newProcedure,
7426
- createdAt: /* @__PURE__ */ new Date(),
7427
- // Use placeholder date for summary creation
7428
- updatedAt: /* @__PURE__ */ new Date()
7429
- });
7430
- const practitionerUpdateData = {
7431
- procedures: (0, import_firestore22.arrayUnion)(procedureId),
7432
- proceduresInfo: (0, import_firestore22.arrayUnion)(procedureSummary),
7433
- updatedAt: (0, import_firestore22.serverTimestamp)()
7434
- };
7435
- batch.update(practitionerRef, practitionerUpdateData);
7436
- const clinicUpdateData = {
7437
- // services: arrayUnion(procedureId), // Decide if 'services' array is still needed
7438
- proceduresInfo: (0, import_firestore22.arrayUnion)(procedureSummary),
7439
- // Potentially update clinic.doctors array if not already present
7440
- doctors: (0, import_firestore22.arrayUnion)(validatedData.practitionerId),
7441
- // Potentially update clinic.doctorsInfo array
7442
- // This requires fetching existing doctorsInfo and adding/updating
7443
- // For simplicity now, we'll just add the procedure summary
7444
- updatedAt: (0, import_firestore22.serverTimestamp)()
7445
- };
7446
- batch.update(clinicRef, clinicUpdateData);
7447
- await batch.commit();
7448
7031
  const savedDoc = await (0, import_firestore22.getDoc)(procedureRef);
7449
7032
  return savedDoc.data();
7450
7033
  }
@@ -7490,7 +7073,7 @@ var ProcedureService = class extends BaseService {
7490
7073
  return snapshot.docs.map((doc28) => doc28.data());
7491
7074
  }
7492
7075
  /**
7493
- * Updates a procedure and its related aggregates in Practitioner and Clinic docs
7076
+ * Updates a procedure
7494
7077
  * @param id - The ID of the procedure to update
7495
7078
  * @param data - The data to update the procedure with
7496
7079
  * @returns The updated procedure
@@ -7607,104 +7190,15 @@ var ProcedureService = class extends BaseService {
7607
7190
  } else if (validatedData.productId) {
7608
7191
  console.warn("Attempted to update product without a valid technologyId");
7609
7192
  }
7610
- const batch = (0, import_firestore22.writeBatch)(this.db);
7611
- batch.update(procedureRef, {
7193
+ await (0, import_firestore22.updateDoc)(procedureRef, {
7612
7194
  ...updatedProcedureData,
7613
7195
  updatedAt: (0, import_firestore22.serverTimestamp)()
7614
7196
  });
7615
- const finalProcedureStateForSummary = {
7616
- ...existingProcedure,
7617
- ...updatedProcedureData,
7618
- // Apply updates
7619
- // Ensure nested objects needed for summary are present
7620
- category: updatedProcedureData.category || existingProcedure.category,
7621
- subcategory: updatedProcedureData.subcategory || existingProcedure.subcategory,
7622
- technology: updatedProcedureData.technology || existingProcedure.technology,
7623
- product: updatedProcedureData.product || existingProcedure.product,
7624
- clinicInfo: updatedProcedureData.clinicInfo || existingProcedure.clinicInfo,
7625
- doctorInfo: updatedProcedureData.doctorInfo || existingProcedure.doctorInfo,
7626
- practitionerId: validatedData.practitionerId || existingProcedure.practitionerId,
7627
- // Use potentially updated IDs
7628
- clinicBranchId: validatedData.clinicBranchId || existingProcedure.clinicBranchId
7629
- };
7630
- const updatedProcedureSummary = this._createProcedureSummaryInfo(
7631
- finalProcedureStateForSummary
7632
- );
7633
- if (practitionerChanged) {
7634
- const oldPractitionerRef = (0, import_firestore22.doc)(
7635
- this.db,
7636
- PRACTITIONERS_COLLECTION,
7637
- oldPractitionerId
7638
- );
7639
- batch.update(oldPractitionerRef, {
7640
- procedures: (0, import_firestore22.arrayRemove)(id),
7641
- proceduresInfo: (0, import_firestore22.arrayRemove)(...[{ id }]),
7642
- // Matcher for removal
7643
- updatedAt: (0, import_firestore22.serverTimestamp)()
7644
- });
7645
- const newPractitionerRef = (0, import_firestore22.doc)(
7646
- this.db,
7647
- PRACTITIONERS_COLLECTION,
7648
- updatedProcedureSummary.practitionerId
7649
- );
7650
- batch.update(newPractitionerRef, {
7651
- procedures: (0, import_firestore22.arrayUnion)(id),
7652
- proceduresInfo: (0, import_firestore22.arrayUnion)(updatedProcedureSummary),
7653
- updatedAt: (0, import_firestore22.serverTimestamp)()
7654
- });
7655
- } else {
7656
- const currentPractitionerRef = (0, import_firestore22.doc)(
7657
- this.db,
7658
- PRACTITIONERS_COLLECTION,
7659
- oldPractitionerId
7660
- );
7661
- batch.update(currentPractitionerRef, {
7662
- proceduresInfo: (0, import_firestore22.arrayRemove)(...[{ id }]),
7663
- updatedAt: (0, import_firestore22.serverTimestamp)()
7664
- });
7665
- batch.update(currentPractitionerRef, {
7666
- proceduresInfo: (0, import_firestore22.arrayUnion)(updatedProcedureSummary),
7667
- updatedAt: (0, import_firestore22.serverTimestamp)()
7668
- });
7669
- }
7670
- if (clinicChanged) {
7671
- const oldClinicRef = (0, import_firestore22.doc)(this.db, CLINICS_COLLECTION, oldClinicId);
7672
- batch.update(oldClinicRef, {
7673
- // services: arrayRemove(id),
7674
- proceduresInfo: (0, import_firestore22.arrayRemove)(...[{ id }]),
7675
- // Matcher for removal
7676
- updatedAt: (0, import_firestore22.serverTimestamp)()
7677
- // Potentially remove from clinic.doctors and clinic.doctorsInfo if practitioner also changed or was last one for this clinic
7678
- });
7679
- const newClinicRef = (0, import_firestore22.doc)(
7680
- this.db,
7681
- CLINICS_COLLECTION,
7682
- updatedProcedureSummary.clinicId
7683
- );
7684
- batch.update(newClinicRef, {
7685
- // services: arrayUnion(id),
7686
- proceduresInfo: (0, import_firestore22.arrayUnion)(updatedProcedureSummary),
7687
- doctors: (0, import_firestore22.arrayUnion)(updatedProcedureSummary.practitionerId),
7688
- // Ensure practitioner is listed
7689
- updatedAt: (0, import_firestore22.serverTimestamp)()
7690
- });
7691
- } else {
7692
- const currentClinicRef = (0, import_firestore22.doc)(this.db, CLINICS_COLLECTION, oldClinicId);
7693
- batch.update(currentClinicRef, {
7694
- proceduresInfo: (0, import_firestore22.arrayRemove)(...[{ id }]),
7695
- updatedAt: (0, import_firestore22.serverTimestamp)()
7696
- });
7697
- batch.update(currentClinicRef, {
7698
- proceduresInfo: (0, import_firestore22.arrayUnion)(updatedProcedureSummary),
7699
- updatedAt: (0, import_firestore22.serverTimestamp)()
7700
- });
7701
- }
7702
- await batch.commit();
7703
7197
  const updatedSnapshot = await (0, import_firestore22.getDoc)(procedureRef);
7704
7198
  return updatedSnapshot.data();
7705
7199
  }
7706
7200
  /**
7707
- * Deactivates a procedure (soft delete) and updates aggregates
7201
+ * Deactivates a procedure (soft delete)
7708
7202
  * @param id - The ID of the procedure to deactivate
7709
7203
  */
7710
7204
  async deactivateProcedure(id) {
@@ -7714,39 +7208,13 @@ var ProcedureService = class extends BaseService {
7714
7208
  console.warn(`Procedure ${id} not found for deactivation.`);
7715
7209
  return;
7716
7210
  }
7717
- const procedure = procedureSnap.data();
7718
- const batch = (0, import_firestore22.writeBatch)(this.db);
7719
- batch.update(procedureRef, {
7211
+ await (0, import_firestore22.updateDoc)(procedureRef, {
7720
7212
  isActive: false,
7721
7213
  updatedAt: (0, import_firestore22.serverTimestamp)()
7722
7214
  });
7723
- const practitionerRef = (0, import_firestore22.doc)(
7724
- this.db,
7725
- PRACTITIONERS_COLLECTION,
7726
- procedure.practitionerId
7727
- );
7728
- batch.update(practitionerRef, {
7729
- procedures: (0, import_firestore22.arrayRemove)(id),
7730
- proceduresInfo: (0, import_firestore22.arrayRemove)(...[{ id }]),
7731
- // Matcher for removal
7732
- updatedAt: (0, import_firestore22.serverTimestamp)()
7733
- });
7734
- const clinicRef = (0, import_firestore22.doc)(
7735
- this.db,
7736
- CLINICS_COLLECTION,
7737
- procedure.clinicBranchId
7738
- );
7739
- batch.update(clinicRef, {
7740
- // services: arrayRemove(id),
7741
- proceduresInfo: (0, import_firestore22.arrayRemove)(...[{ id }]),
7742
- // Matcher for removal
7743
- updatedAt: (0, import_firestore22.serverTimestamp)()
7744
- // Potentially update clinic.doctors/doctorsInfo if this was the last active procedure for this doctor at this clinic
7745
- });
7746
- await batch.commit();
7747
7215
  }
7748
7216
  /**
7749
- * Deletes a procedure permanently and updates related aggregates
7217
+ * Deletes a procedure permanently
7750
7218
  * @param id - The ID of the procedure to delete
7751
7219
  * @returns A boolean indicating if the deletion was successful
7752
7220
  */
@@ -7756,37 +7224,7 @@ var ProcedureService = class extends BaseService {
7756
7224
  if (!procedureSnapshot.exists()) {
7757
7225
  return false;
7758
7226
  }
7759
- const procedure = procedureSnapshot.data();
7760
- const batch = (0, import_firestore22.writeBatch)(this.db);
7761
- if (procedure.practitionerId) {
7762
- const practitionerRef = (0, import_firestore22.doc)(
7763
- this.db,
7764
- PRACTITIONERS_COLLECTION,
7765
- procedure.practitionerId
7766
- );
7767
- batch.update(practitionerRef, {
7768
- procedures: (0, import_firestore22.arrayRemove)(id),
7769
- proceduresInfo: (0, import_firestore22.arrayRemove)(...[{ id }]),
7770
- // Matcher for removal
7771
- updatedAt: (0, import_firestore22.serverTimestamp)()
7772
- });
7773
- }
7774
- if (procedure.clinicBranchId) {
7775
- const clinicRef = (0, import_firestore22.doc)(
7776
- this.db,
7777
- CLINICS_COLLECTION,
7778
- procedure.clinicBranchId
7779
- );
7780
- batch.update(clinicRef, {
7781
- // services: arrayRemove(id),
7782
- proceduresInfo: (0, import_firestore22.arrayRemove)(...[{ id }]),
7783
- // Matcher for removal
7784
- updatedAt: (0, import_firestore22.serverTimestamp)()
7785
- // Potentially update clinic.doctors/doctorsInfo
7786
- });
7787
- }
7788
- batch.delete(procedureRef);
7789
- await batch.commit();
7227
+ await (0, import_firestore22.deleteDoc)(procedureRef);
7790
7228
  return true;
7791
7229
  }
7792
7230
  /**
@@ -7815,20 +7253,20 @@ var ProcedureService = class extends BaseService {
7815
7253
  const proceduresCollection = (0, import_firestore22.collection)(this.db, PROCEDURES_COLLECTION);
7816
7254
  let proceduresQuery = (0, import_firestore22.query)(proceduresCollection);
7817
7255
  if (pagination && pagination > 0) {
7818
- const { limit: limit6, startAfter: startAfter6 } = await import("firebase/firestore");
7256
+ const { limit: limit8, startAfter: startAfter8 } = await import("firebase/firestore");
7819
7257
  if (lastDoc) {
7820
7258
  proceduresQuery = (0, import_firestore22.query)(
7821
7259
  proceduresCollection,
7822
7260
  (0, import_firestore22.orderBy)("name"),
7823
7261
  // Use imported orderBy
7824
- startAfter6(lastDoc),
7825
- limit6(pagination)
7262
+ startAfter8(lastDoc),
7263
+ limit8(pagination)
7826
7264
  );
7827
7265
  } else {
7828
7266
  proceduresQuery = (0, import_firestore22.query)(
7829
7267
  proceduresCollection,
7830
7268
  (0, import_firestore22.orderBy)("name"),
7831
- limit6(pagination)
7269
+ limit8(pagination)
7832
7270
  );
7833
7271
  }
7834
7272
  } else {
@@ -7853,6 +7291,203 @@ var ProcedureService = class extends BaseService {
7853
7291
  throw error;
7854
7292
  }
7855
7293
  }
7294
+ /**
7295
+ * Searches and filters procedures based on multiple criteria
7296
+ *
7297
+ * @param filters - Various filters to apply
7298
+ * @param filters.nameSearch - Optional search text for procedure name
7299
+ * @param filters.treatmentBenefits - Optional array of treatment benefits to filter by
7300
+ * @param filters.procedureFamily - Optional procedure family to filter by
7301
+ * @param filters.procedureCategory - Optional procedure category to filter by
7302
+ * @param filters.procedureSubcategory - Optional procedure subcategory to filter by
7303
+ * @param filters.procedureTechnology - Optional procedure technology to filter by
7304
+ * @param filters.location - Optional location for distance-based search
7305
+ * @param filters.radiusInKm - Optional radius in kilometers (required if location is provided)
7306
+ * @param filters.minPrice - Optional minimum price
7307
+ * @param filters.maxPrice - Optional maximum price
7308
+ * @param filters.minRating - Optional minimum rating (0-5)
7309
+ * @param filters.maxRating - Optional maximum rating (0-5)
7310
+ * @param filters.pagination - Optional number of results per page
7311
+ * @param filters.lastDoc - Optional last document for pagination
7312
+ * @param filters.isActive - Optional filter for active procedures only
7313
+ * @returns Filtered procedures and the last document for pagination
7314
+ */
7315
+ async getProceduresByFilters(filters) {
7316
+ try {
7317
+ console.log(
7318
+ "[PROCEDURE_SERVICE] Starting procedure filtering with criteria:",
7319
+ filters
7320
+ );
7321
+ const isGeoQuery = filters.location && filters.radiusInKm && filters.radiusInKm > 0;
7322
+ const constraints = [];
7323
+ if (filters.isActive !== void 0) {
7324
+ constraints.push((0, import_firestore22.where)("isActive", "==", filters.isActive));
7325
+ } else {
7326
+ constraints.push((0, import_firestore22.where)("isActive", "==", true));
7327
+ }
7328
+ if (filters.procedureFamily) {
7329
+ constraints.push((0, import_firestore22.where)("family", "==", filters.procedureFamily));
7330
+ }
7331
+ constraints.push((0, import_firestore22.orderBy)((0, import_firestore22.documentId)()));
7332
+ if (filters.pagination && filters.pagination > 0 && filters.lastDoc) {
7333
+ constraints.push((0, import_firestore22.startAfter)(filters.lastDoc));
7334
+ constraints.push((0, import_firestore22.limit)(filters.pagination));
7335
+ } else if (filters.pagination && filters.pagination > 0) {
7336
+ constraints.push((0, import_firestore22.limit)(filters.pagination));
7337
+ }
7338
+ let proceduresResult = [];
7339
+ let lastVisibleDoc = null;
7340
+ if (isGeoQuery) {
7341
+ const center = filters.location;
7342
+ const radiusInKm = filters.radiusInKm;
7343
+ const bounds = (0, import_geofire_common8.geohashQueryBounds)(
7344
+ [center.latitude, center.longitude],
7345
+ radiusInKm * 1e3
7346
+ // Convert to meters
7347
+ );
7348
+ const matchingProcedures = [];
7349
+ for (const bound of bounds) {
7350
+ const geoConstraints = [
7351
+ ...constraints,
7352
+ (0, import_firestore22.where)("clinicInfo.location.geohash", ">=", bound[0]),
7353
+ (0, import_firestore22.where)("clinicInfo.location.geohash", "<=", bound[1])
7354
+ ];
7355
+ const q = (0, import_firestore22.query)(
7356
+ (0, import_firestore22.collection)(this.db, PROCEDURES_COLLECTION),
7357
+ ...geoConstraints
7358
+ );
7359
+ const querySnapshot = await (0, import_firestore22.getDocs)(q);
7360
+ console.log(
7361
+ `[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures in geo bound`
7362
+ );
7363
+ for (const doc28 of querySnapshot.docs) {
7364
+ const procedure = { ...doc28.data(), id: doc28.id };
7365
+ const distance = (0, import_geofire_common8.distanceBetween)(
7366
+ [center.latitude, center.longitude],
7367
+ [
7368
+ procedure.clinicInfo.location.latitude,
7369
+ procedure.clinicInfo.location.longitude
7370
+ ]
7371
+ );
7372
+ const distanceInKm = distance / 1e3;
7373
+ if (distanceInKm <= radiusInKm) {
7374
+ matchingProcedures.push({
7375
+ ...procedure,
7376
+ distance: distanceInKm
7377
+ });
7378
+ }
7379
+ }
7380
+ }
7381
+ let filteredProcedures = matchingProcedures;
7382
+ filteredProcedures = this.applyInMemoryFilters(
7383
+ filteredProcedures,
7384
+ filters
7385
+ );
7386
+ filteredProcedures.sort((a, b) => a.distance - b.distance);
7387
+ if (filters.pagination && filters.pagination > 0) {
7388
+ let startIndex = 0;
7389
+ if (filters.lastDoc) {
7390
+ const lastDocIndex = filteredProcedures.findIndex(
7391
+ (procedure) => procedure.id === filters.lastDoc.id
7392
+ );
7393
+ if (lastDocIndex !== -1) {
7394
+ startIndex = lastDocIndex + 1;
7395
+ }
7396
+ }
7397
+ const paginatedProcedures = filteredProcedures.slice(
7398
+ startIndex,
7399
+ startIndex + filters.pagination
7400
+ );
7401
+ lastVisibleDoc = paginatedProcedures.length > 0 ? paginatedProcedures[paginatedProcedures.length - 1] : null;
7402
+ proceduresResult = paginatedProcedures;
7403
+ } else {
7404
+ proceduresResult = filteredProcedures;
7405
+ }
7406
+ } else {
7407
+ const q = (0, import_firestore22.query)(
7408
+ (0, import_firestore22.collection)(this.db, PROCEDURES_COLLECTION),
7409
+ ...constraints
7410
+ );
7411
+ const querySnapshot = await (0, import_firestore22.getDocs)(q);
7412
+ console.log(
7413
+ `[PROCEDURE_SERVICE] Found ${querySnapshot.docs.length} procedures with regular query`
7414
+ );
7415
+ const procedures = querySnapshot.docs.map((doc28) => {
7416
+ return { ...doc28.data(), id: doc28.id };
7417
+ });
7418
+ let filteredProcedures = this.applyInMemoryFilters(procedures, filters);
7419
+ lastVisibleDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
7420
+ proceduresResult = filteredProcedures;
7421
+ }
7422
+ return {
7423
+ procedures: proceduresResult,
7424
+ lastDoc: lastVisibleDoc
7425
+ };
7426
+ } catch (error) {
7427
+ console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
7428
+ throw error;
7429
+ }
7430
+ }
7431
+ /**
7432
+ * Helper method to apply in-memory filters to procedures
7433
+ * Used by getProceduresByFilters to apply filters that can't be done in Firestore queries
7434
+ *
7435
+ * @param procedures - The procedures to filter
7436
+ * @param filters - The filters to apply
7437
+ * @returns Filtered procedures
7438
+ */
7439
+ applyInMemoryFilters(procedures, filters) {
7440
+ let filteredProcedures = procedures;
7441
+ if (filters.nameSearch && filters.nameSearch.trim() !== "") {
7442
+ const searchTerm = filters.nameSearch.toLowerCase().trim();
7443
+ filteredProcedures = filteredProcedures.filter((procedure) => {
7444
+ return procedure.name.toLowerCase().includes(searchTerm);
7445
+ });
7446
+ }
7447
+ if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
7448
+ filteredProcedures = filteredProcedures.filter((procedure) => {
7449
+ return filters.treatmentBenefits.every(
7450
+ (benefit) => procedure.treatmentBenefits.includes(benefit)
7451
+ );
7452
+ });
7453
+ }
7454
+ if (filters.procedureCategory) {
7455
+ filteredProcedures = filteredProcedures.filter(
7456
+ (procedure) => procedure.category.id === filters.procedureCategory
7457
+ );
7458
+ }
7459
+ if (filters.procedureSubcategory) {
7460
+ filteredProcedures = filteredProcedures.filter(
7461
+ (procedure) => procedure.subcategory.id === filters.procedureSubcategory
7462
+ );
7463
+ }
7464
+ if (filters.procedureTechnology) {
7465
+ filteredProcedures = filteredProcedures.filter(
7466
+ (procedure) => procedure.technology.id === filters.procedureTechnology
7467
+ );
7468
+ }
7469
+ if (filters.minPrice !== void 0) {
7470
+ filteredProcedures = filteredProcedures.filter(
7471
+ (procedure) => procedure.price >= filters.minPrice
7472
+ );
7473
+ }
7474
+ if (filters.maxPrice !== void 0) {
7475
+ filteredProcedures = filteredProcedures.filter(
7476
+ (procedure) => procedure.price <= filters.maxPrice
7477
+ );
7478
+ }
7479
+ if (filters.minRating !== void 0) {
7480
+ filteredProcedures = filteredProcedures.filter(
7481
+ (procedure) => procedure.reviewInfo.averageRating >= filters.minRating
7482
+ );
7483
+ }
7484
+ if (filters.maxRating !== void 0) {
7485
+ filteredProcedures = filteredProcedures.filter(
7486
+ (procedure) => procedure.reviewInfo.averageRating <= filters.maxRating
7487
+ );
7488
+ }
7489
+ return filteredProcedures;
7490
+ }
7856
7491
  };
7857
7492
 
7858
7493
  // src/services/documentation-templates/documentation-template.service.ts
@@ -8061,10 +7696,10 @@ var FilledDocumentService = class extends BaseService {
8061
7696
  if (!template) {
8062
7697
  throw new Error(`Template with ID ${templateId} not found`);
8063
7698
  }
8064
- const documentId2 = this.generateId();
7699
+ const documentId3 = this.generateId();
8065
7700
  const now = Date.now();
8066
7701
  const filledDocument = {
8067
- id: documentId2,
7702
+ id: documentId3,
8068
7703
  templateId,
8069
7704
  templateVersion: template.version,
8070
7705
  patientId,
@@ -8075,7 +7710,7 @@ var FilledDocumentService = class extends BaseService {
8075
7710
  values: {},
8076
7711
  status: "draft" /* DRAFT */
8077
7712
  };
8078
- const docRef = (0, import_firestore24.doc)(this.collectionRef, documentId2);
7713
+ const docRef = (0, import_firestore24.doc)(this.collectionRef, documentId3);
8079
7714
  await (0, import_firestore24.setDoc)(docRef, filledDocument);
8080
7715
  return filledDocument;
8081
7716
  }
@@ -8084,8 +7719,8 @@ var FilledDocumentService = class extends BaseService {
8084
7719
  * @param documentId - ID of the filled document to retrieve
8085
7720
  * @returns The filled document or null if not found
8086
7721
  */
8087
- async getFilledDocumentById(documentId2) {
8088
- const docRef = (0, import_firestore24.doc)(this.collectionRef, documentId2);
7722
+ async getFilledDocumentById(documentId3) {
7723
+ const docRef = (0, import_firestore24.doc)(this.collectionRef, documentId3);
8089
7724
  const docSnap = await (0, import_firestore24.getDoc)(docRef);
8090
7725
  if (!docSnap.exists()) {
8091
7726
  return null;
@@ -8099,10 +7734,10 @@ var FilledDocumentService = class extends BaseService {
8099
7734
  * @param status - Optional new status for the document
8100
7735
  * @returns The updated filled document
8101
7736
  */
8102
- async updateFilledDocument(documentId2, values, status) {
8103
- const filledDocument = await this.getFilledDocumentById(documentId2);
7737
+ async updateFilledDocument(documentId3, values, status) {
7738
+ const filledDocument = await this.getFilledDocumentById(documentId3);
8104
7739
  if (!filledDocument) {
8105
- throw new Error(`Filled document with ID ${documentId2} not found`);
7740
+ throw new Error(`Filled document with ID ${documentId3} not found`);
8106
7741
  }
8107
7742
  const updateData = {
8108
7743
  values: {
@@ -8114,7 +7749,7 @@ var FilledDocumentService = class extends BaseService {
8114
7749
  if (status) {
8115
7750
  updateData.status = status;
8116
7751
  }
8117
- const docRef = (0, import_firestore24.doc)(this.collectionRef, documentId2);
7752
+ const docRef = (0, import_firestore24.doc)(this.collectionRef, documentId3);
8118
7753
  await (0, import_firestore24.updateDoc)(docRef, updateData);
8119
7754
  return {
8120
7755
  ...filledDocument,
@@ -8655,37 +8290,19 @@ async function createAppointmentUtil(db, clinicId, practitionerId, patientId, ev
8655
8290
  () => eventId
8656
8291
  // Use the same ID for all calendars
8657
8292
  );
8658
- const [clinicEvent] = await Promise.all([
8659
- clinicPromise,
8660
- practitionerPromise,
8661
- patientPromise
8662
- ]);
8293
+ const [clinicEvent] = await Promise.all([clinicPromise, practitionerPromise, patientPromise]);
8663
8294
  return clinicEvent;
8664
8295
  }
8665
8296
  async function updateAppointmentUtil(db, clinicId, practitionerId, patientId, eventId, updateData) {
8666
- const clinicPromise = updateClinicCalendarEventUtil(
8667
- db,
8668
- clinicId,
8669
- eventId,
8670
- updateData
8671
- );
8297
+ const clinicPromise = updateClinicCalendarEventUtil(db, clinicId, eventId, updateData);
8672
8298
  const practitionerPromise = updatePractitionerCalendarEventUtil(
8673
8299
  db,
8674
8300
  practitionerId,
8675
8301
  eventId,
8676
8302
  updateData
8677
8303
  );
8678
- const patientPromise = updatePatientCalendarEventUtil(
8679
- db,
8680
- patientId,
8681
- eventId,
8682
- updateData
8683
- );
8684
- const [clinicEvent] = await Promise.all([
8685
- clinicPromise,
8686
- practitionerPromise,
8687
- patientPromise
8688
- ]);
8304
+ const patientPromise = updatePatientCalendarEventUtil(db, patientId, eventId, updateData);
8305
+ const [clinicEvent] = await Promise.all([clinicPromise, practitionerPromise, patientPromise]);
8689
8306
  return clinicEvent;
8690
8307
  }
8691
8308