@blackcode_sa/metaestetics-api 1.11.3 → 1.12.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.
Files changed (48) hide show
  1. package/dist/admin/index.d.mts +329 -318
  2. package/dist/admin/index.d.ts +329 -318
  3. package/dist/backoffice/index.d.mts +1166 -430
  4. package/dist/backoffice/index.d.ts +1166 -430
  5. package/dist/backoffice/index.js +1128 -245
  6. package/dist/backoffice/index.mjs +1119 -209
  7. package/dist/index.d.mts +4428 -4035
  8. package/dist/index.d.ts +4428 -4035
  9. package/dist/index.js +1642 -665
  10. package/dist/index.mjs +1406 -401
  11. package/package.json +1 -1
  12. package/src/backoffice/expo-safe/index.ts +3 -0
  13. package/src/backoffice/services/README.md +40 -0
  14. package/src/backoffice/services/brand.service.ts +85 -6
  15. package/src/backoffice/services/category.service.ts +92 -10
  16. package/src/backoffice/services/constants.service.ts +308 -0
  17. package/src/backoffice/services/documentation-template.service.ts +56 -2
  18. package/src/backoffice/services/index.ts +1 -0
  19. package/src/backoffice/services/product.service.ts +126 -5
  20. package/src/backoffice/services/requirement.service.ts +13 -0
  21. package/src/backoffice/services/subcategory.service.ts +184 -13
  22. package/src/backoffice/services/technology.service.ts +344 -129
  23. package/src/backoffice/types/admin-constants.types.ts +69 -0
  24. package/src/backoffice/types/brand.types.ts +1 -0
  25. package/src/backoffice/types/index.ts +1 -0
  26. package/src/backoffice/types/product.types.ts +31 -4
  27. package/src/backoffice/types/static/contraindication.types.ts +1 -0
  28. package/src/backoffice/types/static/treatment-benefit.types.ts +1 -0
  29. package/src/backoffice/types/technology.types.ts +113 -4
  30. package/src/backoffice/validations/schemas.ts +35 -9
  31. package/src/services/appointment/appointment.service.ts +0 -5
  32. package/src/services/appointment/utils/appointment.utils.ts +124 -113
  33. package/src/services/base.service.ts +10 -3
  34. package/src/services/documentation-templates/documentation-template.service.ts +116 -0
  35. package/src/services/media/media.service.ts +2 -2
  36. package/src/services/procedure/procedure.service.ts +436 -234
  37. package/src/types/appointment/index.ts +2 -3
  38. package/src/types/clinic/index.ts +1 -6
  39. package/src/types/patient/medical-info.types.ts +3 -3
  40. package/src/types/procedure/index.ts +20 -17
  41. package/src/validations/clinic.schema.ts +1 -6
  42. package/src/validations/patient/medical-info.schema.ts +7 -2
  43. package/src/backoffice/services/__tests__/brand.service.test.ts +0 -196
  44. package/src/backoffice/services/__tests__/category.service.test.ts +0 -201
  45. package/src/backoffice/services/__tests__/product.service.test.ts +0 -358
  46. package/src/backoffice/services/__tests__/requirement.service.test.ts +0 -226
  47. package/src/backoffice/services/__tests__/subcategory.service.test.ts +0 -181
  48. package/src/backoffice/services/__tests__/technology.service.test.ts +0 -1097
package/dist/index.mjs CHANGED
@@ -17,11 +17,13 @@ import { getFunctions } from "firebase/functions";
17
17
  // src/services/base.service.ts
18
18
  import { getStorage } from "firebase/storage";
19
19
  var BaseService = class {
20
- constructor(db, auth, app) {
20
+ constructor(db, auth, app, storage) {
21
21
  this.db = db;
22
22
  this.auth = auth;
23
23
  this.app = app;
24
- this.storage = getStorage(app);
24
+ if (app) {
25
+ this.storage = storage || getStorage(app);
26
+ }
25
27
  }
26
28
  /**
27
29
  * Generiše jedinstveni ID za dokumente
@@ -53,13 +55,13 @@ var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
53
55
  AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
54
56
  return AppointmentStatus2;
55
57
  })(AppointmentStatus || {});
56
- var PaymentStatus = /* @__PURE__ */ ((PaymentStatus3) => {
57
- PaymentStatus3["UNPAID"] = "unpaid";
58
- PaymentStatus3["PAID"] = "paid";
59
- PaymentStatus3["PARTIALLY_PAID"] = "partially_paid";
60
- PaymentStatus3["REFUNDED"] = "refunded";
61
- PaymentStatus3["NOT_APPLICABLE"] = "not_applicable";
62
- return PaymentStatus3;
58
+ var PaymentStatus = /* @__PURE__ */ ((PaymentStatus4) => {
59
+ PaymentStatus4["UNPAID"] = "unpaid";
60
+ PaymentStatus4["PAID"] = "paid";
61
+ PaymentStatus4["PARTIALLY_PAID"] = "partially_paid";
62
+ PaymentStatus4["REFUNDED"] = "refunded";
63
+ PaymentStatus4["NOT_APPLICABLE"] = "not_applicable";
64
+ return PaymentStatus4;
63
65
  })(PaymentStatus || {});
64
66
  var MediaType = /* @__PURE__ */ ((MediaType2) => {
65
67
  MediaType2["BEFORE_PHOTO"] = "before_photo";
@@ -582,7 +584,6 @@ import {
582
584
  getDocs,
583
585
  query,
584
586
  where,
585
- setDoc,
586
587
  updateDoc,
587
588
  serverTimestamp,
588
589
  Timestamp,
@@ -819,44 +820,48 @@ async function updateAppointmentUtil(db, appointmentId, data) {
819
820
  const validPreReqIds = currentAppointment.preProcedureRequirements.map(
820
821
  (req) => req.id
821
822
  );
822
- const invalidPreReqIds = data.completedPreRequirements.filter(
823
- (id) => !validPreReqIds.includes(id)
824
- );
825
- if (invalidPreReqIds.length > 0) {
826
- throw new Error(
827
- `Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
823
+ if (Array.isArray(data.completedPreRequirements)) {
824
+ const invalidPreReqIds = data.completedPreRequirements.filter(
825
+ (id) => !validPreReqIds.includes(id)
828
826
  );
827
+ if (invalidPreReqIds.length > 0) {
828
+ throw new Error(
829
+ `Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
830
+ );
831
+ }
832
+ completedPreRequirements = [
833
+ .../* @__PURE__ */ new Set([
834
+ ...completedPreRequirements,
835
+ ...data.completedPreRequirements
836
+ ])
837
+ ];
829
838
  }
830
- completedPreRequirements = [
831
- .../* @__PURE__ */ new Set([
832
- ...completedPreRequirements,
833
- ...data.completedPreRequirements
834
- ])
835
- ];
836
839
  }
837
840
  if (data.completedPostRequirements) {
838
841
  const validPostReqIds = currentAppointment.postProcedureRequirements.map(
839
842
  (req) => req.id
840
843
  );
841
- const invalidPostReqIds = data.completedPostRequirements.filter(
842
- (id) => !validPostReqIds.includes(id)
843
- );
844
- if (invalidPostReqIds.length > 0) {
845
- throw new Error(
846
- `Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
844
+ if (Array.isArray(data.completedPostRequirements)) {
845
+ const invalidPostReqIds = data.completedPostRequirements.filter(
846
+ (id) => !validPostReqIds.includes(id)
847
847
  );
848
+ if (invalidPostReqIds.length > 0) {
849
+ throw new Error(
850
+ `Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
851
+ );
852
+ }
853
+ completedPostRequirements = [
854
+ .../* @__PURE__ */ new Set([
855
+ ...completedPostRequirements,
856
+ ...data.completedPostRequirements
857
+ ])
858
+ ];
848
859
  }
849
- completedPostRequirements = [
850
- .../* @__PURE__ */ new Set([
851
- ...completedPostRequirements,
852
- ...data.completedPostRequirements
853
- ])
854
- ];
855
860
  }
856
861
  const updateData = {
857
862
  ...data,
858
- completedPreRequirements,
859
- completedPostRequirements,
863
+ completedPreRequirements: Array.isArray(data.completedPreRequirements) ? completedPreRequirements : data.completedPreRequirements,
864
+ completedPostRequirements: Array.isArray(data.completedPostRequirements) ? completedPostRequirements : data.completedPostRequirements,
860
865
  updatedAt: serverTimestamp()
861
866
  };
862
867
  Object.keys(updateData).forEach((key) => {
@@ -906,7 +911,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
906
911
  case "canceled_clinic" /* CANCELED_CLINIC */:
907
912
  calendarStatus = "canceled";
908
913
  break;
909
- case AppointmentStatus.RESCHEDULED:
914
+ case "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */:
910
915
  calendarStatus = "rescheduled";
911
916
  break;
912
917
  case "completed" /* COMPLETED */:
@@ -980,7 +985,7 @@ async function searchAppointmentsUtil(db, params) {
980
985
  const q = query(collection(db, APPOINTMENTS_COLLECTION), ...constraints);
981
986
  const querySnapshot = await getDocs(q);
982
987
  const appointments = querySnapshot.docs.map(
983
- (doc37) => doc37.data()
988
+ (doc38) => doc38.data()
984
989
  );
985
990
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
986
991
  return { appointments, lastDoc };
@@ -1787,7 +1792,7 @@ var AppointmentService = class extends BaseService {
1787
1792
  );
1788
1793
  const querySnapshot = await getDocs2(q);
1789
1794
  const appointments = querySnapshot.docs.map(
1790
- (doc37) => doc37.data()
1795
+ (doc38) => doc38.data()
1791
1796
  );
1792
1797
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1793
1798
  console.log(
@@ -1860,7 +1865,7 @@ var AppointmentService = class extends BaseService {
1860
1865
  );
1861
1866
  const querySnapshot = await getDocs2(q);
1862
1867
  const appointments = querySnapshot.docs.map(
1863
- (doc37) => doc37.data()
1868
+ (doc38) => doc38.data()
1864
1869
  );
1865
1870
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1866
1871
  console.log(
@@ -2412,8 +2417,8 @@ var MediaAccessLevel = /* @__PURE__ */ ((MediaAccessLevel2) => {
2412
2417
  })(MediaAccessLevel || {});
2413
2418
  var MEDIA_METADATA_COLLECTION = "media_metadata";
2414
2419
  var MediaService = class extends BaseService {
2415
- constructor(db, auth, app) {
2416
- super(db, auth, app);
2420
+ constructor(...args) {
2421
+ super(...args);
2417
2422
  }
2418
2423
  /**
2419
2424
  * Upload a media file, store its metadata, and return the metadata including the URL.
@@ -2673,7 +2678,7 @@ var MediaService = class extends BaseService {
2673
2678
  try {
2674
2679
  const querySnapshot = await getDocs3(finalQuery);
2675
2680
  const mediaList = querySnapshot.docs.map(
2676
- (doc37) => doc37.data()
2681
+ (doc38) => doc38.data()
2677
2682
  );
2678
2683
  console.log(`[MediaService] Found ${mediaList.length} media items.`);
2679
2684
  return mediaList;
@@ -2736,8 +2741,8 @@ var getPatientsByClinicUtil = async (db, clinicId, options) => {
2736
2741
  }
2737
2742
  const patientsSnapshot = await getDocs4(q);
2738
2743
  const patients = [];
2739
- patientsSnapshot.forEach((doc37) => {
2740
- patients.push(doc37.data());
2744
+ patientsSnapshot.forEach((doc38) => {
2745
+ patients.push(doc38.data());
2741
2746
  });
2742
2747
  console.log(
2743
2748
  `[getPatientsByClinicUtil] Found ${patients.length} patients for clinic ID: ${clinicId}`
@@ -2799,23 +2804,6 @@ var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
2799
2804
  return BlockingCondition2;
2800
2805
  })(BlockingCondition || {});
2801
2806
 
2802
- // src/backoffice/types/static/contraindication.types.ts
2803
- var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
2804
- Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
2805
- Contraindication2["RECENT_TANNING"] = "recent_tanning";
2806
- Contraindication2["RECENT_BOTOX"] = "recent_botox";
2807
- Contraindication2["RECENT_FILLERS"] = "recent_fillers";
2808
- Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
2809
- Contraindication2["MEDICATIONS"] = "medications";
2810
- Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
2811
- Contraindication2["RECENT_LASER"] = "recent_laser";
2812
- Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
2813
- Contraindication2["OPEN_WOUNDS"] = "open_wounds";
2814
- Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
2815
- Contraindication2["COLD_SORES"] = "cold_sores";
2816
- return Contraindication2;
2817
- })(Contraindication || {});
2818
-
2819
2807
  // src/validations/common.schema.ts
2820
2808
  import { z as z5 } from "zod";
2821
2809
  import { Timestamp as Timestamp4 } from "firebase/firestore";
@@ -2870,8 +2858,13 @@ var blockingConditionSchema = z6.object({
2870
2858
  notes: z6.string().optional().nullable(),
2871
2859
  isActive: z6.boolean()
2872
2860
  });
2861
+ var contraindicationDynamicSchema = z6.object({
2862
+ id: z6.string(),
2863
+ name: z6.string(),
2864
+ description: z6.string().optional()
2865
+ });
2873
2866
  var contraindicationSchema = z6.object({
2874
- condition: z6.nativeEnum(Contraindication),
2867
+ condition: contraindicationDynamicSchema,
2875
2868
  lastOccurrence: timestampSchema,
2876
2869
  frequency: z6.enum(["rare", "occasional", "frequent"]),
2877
2870
  notes: z6.string().optional().nullable(),
@@ -3111,8 +3104,8 @@ var getPatientsByPractitionerUtil = async (db, practitionerId, options) => {
3111
3104
  }
3112
3105
  const patientsSnapshot = await getDocs5(q);
3113
3106
  const patients = [];
3114
- patientsSnapshot.forEach((doc37) => {
3115
- patients.push(doc37.data());
3107
+ patientsSnapshot.forEach((doc38) => {
3108
+ patients.push(doc38.data());
3116
3109
  });
3117
3110
  console.log(
3118
3111
  `[getPatientsByPractitionerUtil] Found ${patients.length} patients for practitioner ID: ${practitionerId}`
@@ -3891,7 +3884,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
3891
3884
  where6("clinicGroupId", "==", clinicGroupId)
3892
3885
  );
3893
3886
  const querySnapshot = await getDocs6(q);
3894
- return querySnapshot.docs.map((doc37) => doc37.data());
3887
+ return querySnapshot.docs.map((doc38) => doc38.data());
3895
3888
  }
3896
3889
  async function updateClinicAdmin(db, adminId, data) {
3897
3890
  const admin = await getClinicAdmin(db, adminId);
@@ -4572,9 +4565,9 @@ var updateAllergyUtil = async (db, patientId, data, requesterId, requesterRoles)
4572
4565
  };
4573
4566
  var removeAllergyUtil = async (db, patientId, allergyIndex, requesterId, requesterRoles) => {
4574
4567
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4575
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4576
- if (!doc37.exists()) throw new Error("Medical info not found");
4577
- const medicalInfo = doc37.data();
4568
+ const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4569
+ if (!doc38.exists()) throw new Error("Medical info not found");
4570
+ const medicalInfo = doc38.data();
4578
4571
  if (allergyIndex >= medicalInfo.allergies.length) {
4579
4572
  throw new Error("Invalid allergy index");
4580
4573
  }
@@ -4601,9 +4594,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, requesterId, reque
4601
4594
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4602
4595
  const validatedData = updateBlockingConditionSchema.parse(data);
4603
4596
  const { conditionIndex, ...updateData } = validatedData;
4604
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4605
- if (!doc37.exists()) throw new Error("Medical info not found");
4606
- const medicalInfo = doc37.data();
4597
+ const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4598
+ if (!doc38.exists()) throw new Error("Medical info not found");
4599
+ const medicalInfo = doc38.data();
4607
4600
  if (conditionIndex >= medicalInfo.blockingConditions.length) {
4608
4601
  throw new Error("Invalid blocking condition index");
4609
4602
  }
@@ -4620,9 +4613,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, requesterId, reque
4620
4613
  };
4621
4614
  var removeBlockingConditionUtil = async (db, patientId, conditionIndex, requesterId, requesterRoles) => {
4622
4615
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4623
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4624
- if (!doc37.exists()) throw new Error("Medical info not found");
4625
- const medicalInfo = doc37.data();
4616
+ const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4617
+ if (!doc38.exists()) throw new Error("Medical info not found");
4618
+ const medicalInfo = doc38.data();
4626
4619
  if (conditionIndex >= medicalInfo.blockingConditions.length) {
4627
4620
  throw new Error("Invalid blocking condition index");
4628
4621
  }
@@ -4649,9 +4642,9 @@ var updateContraindicationUtil = async (db, patientId, data, requesterId, reques
4649
4642
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4650
4643
  const validatedData = updateContraindicationSchema.parse(data);
4651
4644
  const { contraindicationIndex, ...updateData } = validatedData;
4652
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4653
- if (!doc37.exists()) throw new Error("Medical info not found");
4654
- const medicalInfo = doc37.data();
4645
+ const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4646
+ if (!doc38.exists()) throw new Error("Medical info not found");
4647
+ const medicalInfo = doc38.data();
4655
4648
  if (contraindicationIndex >= medicalInfo.contraindications.length) {
4656
4649
  throw new Error("Invalid contraindication index");
4657
4650
  }
@@ -4668,9 +4661,9 @@ var updateContraindicationUtil = async (db, patientId, data, requesterId, reques
4668
4661
  };
4669
4662
  var removeContraindicationUtil = async (db, patientId, contraindicationIndex, requesterId, requesterRoles) => {
4670
4663
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4671
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4672
- if (!doc37.exists()) throw new Error("Medical info not found");
4673
- const medicalInfo = doc37.data();
4664
+ const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4665
+ if (!doc38.exists()) throw new Error("Medical info not found");
4666
+ const medicalInfo = doc38.data();
4674
4667
  if (contraindicationIndex >= medicalInfo.contraindications.length) {
4675
4668
  throw new Error("Invalid contraindication index");
4676
4669
  }
@@ -4697,9 +4690,9 @@ var updateMedicationUtil = async (db, patientId, data, requesterId, requesterRol
4697
4690
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4698
4691
  const validatedData = updateMedicationSchema.parse(data);
4699
4692
  const { medicationIndex, ...updateData } = validatedData;
4700
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4701
- if (!doc37.exists()) throw new Error("Medical info not found");
4702
- const medicalInfo = doc37.data();
4693
+ const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4694
+ if (!doc38.exists()) throw new Error("Medical info not found");
4695
+ const medicalInfo = doc38.data();
4703
4696
  if (medicationIndex >= medicalInfo.currentMedications.length) {
4704
4697
  throw new Error("Invalid medication index");
4705
4698
  }
@@ -4716,9 +4709,9 @@ var updateMedicationUtil = async (db, patientId, data, requesterId, requesterRol
4716
4709
  };
4717
4710
  var removeMedicationUtil = async (db, patientId, medicationIndex, requesterId, requesterRoles) => {
4718
4711
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4719
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4720
- if (!doc37.exists()) throw new Error("Medical info not found");
4721
- const medicalInfo = doc37.data();
4712
+ const doc38 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4713
+ if (!doc38.exists()) throw new Error("Medical info not found");
4714
+ const medicalInfo = doc38.data();
4722
4715
  if (medicationIndex >= medicalInfo.currentMedications.length) {
4723
4716
  throw new Error("Invalid medication index");
4724
4717
  }
@@ -5021,7 +5014,7 @@ var searchPatientsUtil = async (db, params, requester) => {
5021
5014
  const finalQuery = query8(patientsCollectionRef, ...constraints);
5022
5015
  const querySnapshot = await getDocs8(finalQuery);
5023
5016
  const patients = querySnapshot.docs.map(
5024
- (doc37) => doc37.data()
5017
+ (doc38) => doc38.data()
5025
5018
  );
5026
5019
  console.log(
5027
5020
  `[searchPatientsUtil] Found ${patients.length} patients matching criteria.`
@@ -5053,8 +5046,8 @@ var getAllPatientsUtil = async (db, options) => {
5053
5046
  }
5054
5047
  const patientsSnapshot = await getDocs8(q);
5055
5048
  const patients = [];
5056
- patientsSnapshot.forEach((doc37) => {
5057
- patients.push(doc37.data());
5049
+ patientsSnapshot.forEach((doc38) => {
5050
+ patients.push(doc38.data());
5058
5051
  });
5059
5052
  console.log(`[getAllPatientsUtil] Found ${patients.length} patients`);
5060
5053
  return patients;
@@ -5187,7 +5180,7 @@ var getActiveInviteTokensByClinicUtil = async (db, clinicId) => {
5187
5180
  if (querySnapshot.empty) {
5188
5181
  return [];
5189
5182
  }
5190
- return querySnapshot.docs.map((doc37) => doc37.data());
5183
+ return querySnapshot.docs.map((doc38) => doc38.data());
5191
5184
  };
5192
5185
  var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
5193
5186
  const tokensRef = collection9(
@@ -5205,7 +5198,7 @@ var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
5205
5198
  if (querySnapshot.empty) {
5206
5199
  return [];
5207
5200
  }
5208
- return querySnapshot.docs.map((doc37) => doc37.data());
5201
+ return querySnapshot.docs.map((doc38) => doc38.data());
5209
5202
  };
5210
5203
 
5211
5204
  // src/services/patient/patient.service.ts
@@ -6494,7 +6487,7 @@ var PractitionerService = class extends BaseService {
6494
6487
  where10("expiresAt", ">", Timestamp14.now())
6495
6488
  );
6496
6489
  const querySnapshot = await getDocs10(q);
6497
- return querySnapshot.docs.map((doc37) => doc37.data());
6490
+ return querySnapshot.docs.map((doc38) => doc38.data());
6498
6491
  }
6499
6492
  /**
6500
6493
  * Gets a token by its string value and validates it
@@ -6604,7 +6597,7 @@ var PractitionerService = class extends BaseService {
6604
6597
  where10("status", "==", "active" /* ACTIVE */)
6605
6598
  );
6606
6599
  const querySnapshot = await getDocs10(q);
6607
- return querySnapshot.docs.map((doc37) => doc37.data());
6600
+ return querySnapshot.docs.map((doc38) => doc38.data());
6608
6601
  }
6609
6602
  /**
6610
6603
  * Dohvata sve zdravstvene radnike za određenu kliniku
@@ -6616,7 +6609,7 @@ var PractitionerService = class extends BaseService {
6616
6609
  where10("isActive", "==", true)
6617
6610
  );
6618
6611
  const querySnapshot = await getDocs10(q);
6619
- return querySnapshot.docs.map((doc37) => doc37.data());
6612
+ return querySnapshot.docs.map((doc38) => doc38.data());
6620
6613
  }
6621
6614
  /**
6622
6615
  * Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
@@ -6628,7 +6621,7 @@ var PractitionerService = class extends BaseService {
6628
6621
  where10("status", "==", "draft" /* DRAFT */)
6629
6622
  );
6630
6623
  const querySnapshot = await getDocs10(q);
6631
- return querySnapshot.docs.map((doc37) => doc37.data());
6624
+ return querySnapshot.docs.map((doc38) => doc38.data());
6632
6625
  }
6633
6626
  /**
6634
6627
  * Updates a practitioner
@@ -6843,7 +6836,7 @@ var PractitionerService = class extends BaseService {
6843
6836
  );
6844
6837
  const querySnapshot = await getDocs10(q);
6845
6838
  const practitioners = querySnapshot.docs.map(
6846
- (doc37) => doc37.data()
6839
+ (doc38) => doc38.data()
6847
6840
  );
6848
6841
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
6849
6842
  return {
@@ -6917,7 +6910,7 @@ var PractitionerService = class extends BaseService {
6917
6910
  constraints.push(limit7(filters.pagination || 10));
6918
6911
  const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
6919
6912
  const querySnapshot = await getDocs10(q);
6920
- const practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
6913
+ const practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
6921
6914
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
6922
6915
  console.log(`[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`);
6923
6916
  if (practitioners.length < (filters.pagination || 10)) {
@@ -6964,7 +6957,7 @@ var PractitionerService = class extends BaseService {
6964
6957
  }
6965
6958
  const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
6966
6959
  const querySnapshot = await getDocs10(q);
6967
- let practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
6960
+ let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
6968
6961
  if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
6969
6962
  const location = filters.location;
6970
6963
  const radiusInKm = filters.radiusInKm;
@@ -7000,7 +6993,7 @@ var PractitionerService = class extends BaseService {
7000
6993
  ];
7001
6994
  const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
7002
6995
  const querySnapshot = await getDocs10(q);
7003
- let practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
6996
+ let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
7004
6997
  practitioners = this.applyInMemoryFilters(practitioners, filters);
7005
6998
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
7006
6999
  console.log(`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`);
@@ -7021,7 +7014,7 @@ var PractitionerService = class extends BaseService {
7021
7014
  ];
7022
7015
  const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
7023
7016
  const querySnapshot = await getDocs10(q);
7024
- let practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
7017
+ let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
7025
7018
  practitioners = this.applyInMemoryFilters(practitioners, filters);
7026
7019
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
7027
7020
  console.log(`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`);
@@ -7536,7 +7529,7 @@ var UserService = class extends BaseService {
7536
7529
  ];
7537
7530
  const q = query11(collection11(this.db, USERS_COLLECTION), ...constraints);
7538
7531
  const querySnapshot = await getDocs11(q);
7539
- const users = querySnapshot.docs.map((doc37) => doc37.data());
7532
+ const users = querySnapshot.docs.map((doc38) => doc38.data());
7540
7533
  return users.map((userData) => userSchema.parse(userData));
7541
7534
  }
7542
7535
  /**
@@ -7916,7 +7909,7 @@ async function getAllActiveGroups(db) {
7916
7909
  where12("isActive", "==", true)
7917
7910
  );
7918
7911
  const querySnapshot = await getDocs12(q);
7919
- return querySnapshot.docs.map((doc37) => doc37.data());
7912
+ return querySnapshot.docs.map((doc38) => doc38.data());
7920
7913
  }
7921
7914
  async function updateClinicGroup(db, groupId, data, app) {
7922
7915
  console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
@@ -8384,7 +8377,7 @@ async function getClinicsByGroup(db, groupId) {
8384
8377
  where13("isActive", "==", true)
8385
8378
  );
8386
8379
  const querySnapshot = await getDocs13(q);
8387
- return querySnapshot.docs.map((doc37) => doc37.data());
8380
+ return querySnapshot.docs.map((doc38) => doc38.data());
8388
8381
  }
8389
8382
  async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
8390
8383
  console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
@@ -8578,7 +8571,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
8578
8571
  }
8579
8572
  const q = query13(collection13(db, CLINICS_COLLECTION), ...constraints);
8580
8573
  const querySnapshot = await getDocs13(q);
8581
- return querySnapshot.docs.map((doc37) => doc37.data());
8574
+ return querySnapshot.docs.map((doc38) => doc38.data());
8582
8575
  }
8583
8576
  async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
8584
8577
  return getClinicsByAdmin(
@@ -8623,11 +8616,11 @@ async function getAllClinics(db, pagination, lastDoc) {
8623
8616
  }
8624
8617
  const clinicsSnapshot = await getDocs13(clinicsQuery);
8625
8618
  const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
8626
- const clinics = clinicsSnapshot.docs.map((doc37) => {
8627
- const data = doc37.data();
8619
+ const clinics = clinicsSnapshot.docs.map((doc38) => {
8620
+ const data = doc38.data();
8628
8621
  return {
8629
8622
  ...data,
8630
- id: doc37.id
8623
+ id: doc38.id
8631
8624
  };
8632
8625
  });
8633
8626
  return {
@@ -8654,8 +8647,8 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
8654
8647
  ];
8655
8648
  const q = query13(collection13(db, CLINICS_COLLECTION), ...constraints);
8656
8649
  const querySnapshot = await getDocs13(q);
8657
- for (const doc37 of querySnapshot.docs) {
8658
- const clinic = doc37.data();
8650
+ for (const doc38 of querySnapshot.docs) {
8651
+ const clinic = doc38.data();
8659
8652
  const distance = distanceBetween2(
8660
8653
  [center.latitude, center.longitude],
8661
8654
  [clinic.location.latitude, clinic.location.longitude]
@@ -8777,8 +8770,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
8777
8770
  }
8778
8771
  const q = query14(collection14(db, CLINICS_COLLECTION), ...constraints);
8779
8772
  const querySnapshot = await getDocs14(q);
8780
- for (const doc37 of querySnapshot.docs) {
8781
- const clinic = doc37.data();
8773
+ for (const doc38 of querySnapshot.docs) {
8774
+ const clinic = doc38.data();
8782
8775
  const distance = distanceBetween3(
8783
8776
  [center.latitude, center.longitude],
8784
8777
  [clinic.location.latitude, clinic.location.longitude]
@@ -8907,7 +8900,7 @@ async function getClinicsByFilters(db, filters) {
8907
8900
  constraints.push(limit9(filters.pagination || 5));
8908
8901
  const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8909
8902
  const querySnapshot = await getDocs15(q);
8910
- let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8903
+ let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
8911
8904
  clinics = applyInMemoryFilters(clinics, filters);
8912
8905
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8913
8906
  console.log(`[CLINIC_SERVICE] Strategy 1 success: ${clinics.length} clinics`);
@@ -8939,7 +8932,7 @@ async function getClinicsByFilters(db, filters) {
8939
8932
  constraints.push(limit9(filters.pagination || 5));
8940
8933
  const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8941
8934
  const querySnapshot = await getDocs15(q);
8942
- let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8935
+ let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
8943
8936
  clinics = applyInMemoryFilters(clinics, filters);
8944
8937
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8945
8938
  console.log(`[CLINIC_SERVICE] Strategy 2 success: ${clinics.length} clinics`);
@@ -8969,7 +8962,7 @@ async function getClinicsByFilters(db, filters) {
8969
8962
  constraints.push(limit9(filters.pagination || 5));
8970
8963
  const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8971
8964
  const querySnapshot = await getDocs15(q);
8972
- let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8965
+ let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
8973
8966
  clinics = applyInMemoryFilters(clinics, filters);
8974
8967
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8975
8968
  console.log(`[CLINIC_SERVICE] Strategy 3 success: ${clinics.length} clinics`);
@@ -8989,7 +8982,7 @@ async function getClinicsByFilters(db, filters) {
8989
8982
  ];
8990
8983
  const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8991
8984
  const querySnapshot = await getDocs15(q);
8992
- let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8985
+ let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
8993
8986
  clinics = applyInMemoryFilters(clinics, filters);
8994
8987
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8995
8988
  console.log(`[CLINIC_SERVICE] Strategy 4 success: ${clinics.length} clinics`);
@@ -9565,11 +9558,11 @@ var ClinicService = class extends BaseService {
9565
9558
  async getClinicsForMap() {
9566
9559
  const clinicsRef = collection16(this.db, CLINICS_COLLECTION);
9567
9560
  const snapshot = await getDocs16(clinicsRef);
9568
- const clinicsForMap = snapshot.docs.map((doc37) => {
9561
+ const clinicsForMap = snapshot.docs.map((doc38) => {
9569
9562
  var _a, _b, _c;
9570
- const data = doc37.data();
9563
+ const data = doc38.data();
9571
9564
  return {
9572
- id: doc37.id,
9565
+ id: doc38.id,
9573
9566
  name: data.name,
9574
9567
  address: ((_a = data.location) == null ? void 0 : _a.address) || "",
9575
9568
  latitude: (_b = data.location) == null ? void 0 : _b.latitude,
@@ -10776,7 +10769,7 @@ async function updatePractitionerCalendarEventUtil(db, practitionerId, eventId,
10776
10769
  }
10777
10770
 
10778
10771
  // src/services/calendar/utils/appointment.utils.ts
10779
- async function createAppointmentUtil2(db, clinicId, practitionerId, patientId, eventData, generateId2) {
10772
+ async function createAppointmentUtil(db, clinicId, practitionerId, patientId, eventData, generateId2) {
10780
10773
  const eventId = generateId2();
10781
10774
  const autoConfirm = await checkAutoConfirmAppointmentsUtil(db, clinicId);
10782
10775
  const initialStatus = autoConfirm ? "confirmed" /* CONFIRMED */ : "pending" /* PENDING */;
@@ -10923,7 +10916,7 @@ async function searchCalendarEventsUtil(db, params) {
10923
10916
  const finalQuery = query21(collectionRef, ...constraints);
10924
10917
  const querySnapshot = await getDocs21(finalQuery);
10925
10918
  const events = querySnapshot.docs.map(
10926
- (doc37) => ({ id: doc37.id, ...doc37.data() })
10919
+ (doc38) => ({ id: doc38.id, ...doc38.data() })
10927
10920
  );
10928
10921
  return events;
10929
10922
  } catch (error) {
@@ -11016,7 +11009,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
11016
11009
  );
11017
11010
  const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
11018
11011
  const querySnapshot = await getDocs22(q);
11019
- return querySnapshot.docs.map((doc37) => doc37.data());
11012
+ return querySnapshot.docs.map((doc38) => doc38.data());
11020
11013
  }
11021
11014
  async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
11022
11015
  const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
@@ -11033,7 +11026,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
11033
11026
  );
11034
11027
  const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
11035
11028
  const querySnapshot = await getDocs22(q);
11036
- return querySnapshot.docs.map((doc37) => doc37.data());
11029
+ return querySnapshot.docs.map((doc38) => doc38.data());
11037
11030
  }
11038
11031
  async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
11039
11032
  const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
@@ -11050,7 +11043,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
11050
11043
  );
11051
11044
  const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
11052
11045
  const querySnapshot = await getDocs22(q);
11053
- return querySnapshot.docs.map((doc37) => doc37.data());
11046
+ return querySnapshot.docs.map((doc38) => doc38.data());
11054
11047
  }
11055
11048
  async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
11056
11049
  const calendarRef = getPractitionerSyncedCalendarDocRef(
@@ -12118,7 +12111,7 @@ var CalendarServiceV2 = class extends BaseService {
12118
12111
  syncStatus: "internal" /* INTERNAL */,
12119
12112
  eventType: "appointment" /* APPOINTMENT */
12120
12113
  };
12121
- const appointment = await createAppointmentUtil2(
12114
+ const appointment = await createAppointmentUtil(
12122
12115
  this.db,
12123
12116
  params.clinicId,
12124
12117
  params.doctorId,
@@ -12405,9 +12398,9 @@ var CalendarServiceV2 = class extends BaseService {
12405
12398
  where23("eventTime.start", "<=", Timestamp26.fromDate(endDate))
12406
12399
  );
12407
12400
  const eventsSnapshot = await getDocs23(q);
12408
- const events = eventsSnapshot.docs.map((doc37) => ({
12409
- id: doc37.id,
12410
- ...doc37.data()
12401
+ const events = eventsSnapshot.docs.map((doc38) => ({
12402
+ id: doc38.id,
12403
+ ...doc38.data()
12411
12404
  }));
12412
12405
  const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
12413
12406
  doctorId
@@ -13041,7 +13034,7 @@ var CalendarServiceV2 = class extends BaseService {
13041
13034
  ])
13042
13035
  );
13043
13036
  const querySnapshot = await getDocs23(q);
13044
- return querySnapshot.docs.map((doc37) => doc37.data());
13037
+ return querySnapshot.docs.map((doc38) => doc38.data());
13045
13038
  }
13046
13039
  /**
13047
13040
  * Calculates available time slots based on working hours, schedule and existing appointments
@@ -13586,7 +13579,7 @@ var PractitionerInviteService = class extends BaseService {
13586
13579
  ...constraints
13587
13580
  );
13588
13581
  const querySnapshot = await getDocs24(q);
13589
- return querySnapshot.docs.map((doc37) => doc37.data());
13582
+ return querySnapshot.docs.map((doc38) => doc38.data());
13590
13583
  } catch (error) {
13591
13584
  console.error(
13592
13585
  "[PractitionerInviteService] Error getting doctor invites:",
@@ -13615,7 +13608,7 @@ var PractitionerInviteService = class extends BaseService {
13615
13608
  ...constraints
13616
13609
  );
13617
13610
  const querySnapshot = await getDocs24(q);
13618
- return querySnapshot.docs.map((doc37) => doc37.data());
13611
+ return querySnapshot.docs.map((doc38) => doc38.data());
13619
13612
  } catch (error) {
13620
13613
  console.error(
13621
13614
  "[PractitionerInviteService] Error getting clinic invites:",
@@ -13771,7 +13764,7 @@ var PractitionerInviteService = class extends BaseService {
13771
13764
  );
13772
13765
  const querySnapshot = await getDocs24(q);
13773
13766
  let invites = querySnapshot.docs.map(
13774
- (doc37) => doc37.data()
13767
+ (doc38) => doc38.data()
13775
13768
  );
13776
13769
  if (filters.fromDate) {
13777
13770
  invites = invites.filter(
@@ -13887,9 +13880,10 @@ import {
13887
13880
  limit as limit12,
13888
13881
  startAfter as startAfter10
13889
13882
  } from "firebase/firestore";
13883
+ import { getCountFromServer } from "firebase/firestore";
13890
13884
  var DocumentationTemplateService = class extends BaseService {
13891
- constructor() {
13892
- super(...arguments);
13885
+ constructor(...args) {
13886
+ super(...args);
13893
13887
  this.collectionRef = collection25(
13894
13888
  this.db,
13895
13889
  DOCUMENTATION_TEMPLATES_COLLECTION
@@ -14041,8 +14035,8 @@ var DocumentationTemplateService = class extends BaseService {
14041
14035
  const q = query25(versionsCollectionRef, orderBy13("version", "desc"));
14042
14036
  const querySnapshot = await getDocs25(q);
14043
14037
  const versions = [];
14044
- querySnapshot.forEach((doc37) => {
14045
- versions.push(doc37.data());
14038
+ querySnapshot.forEach((doc38) => {
14039
+ versions.push(doc38.data());
14046
14040
  });
14047
14041
  return versions;
14048
14042
  }
@@ -14073,15 +14067,97 @@ var DocumentationTemplateService = class extends BaseService {
14073
14067
  const querySnapshot = await getDocs25(q);
14074
14068
  const templates = [];
14075
14069
  let lastVisible = null;
14076
- querySnapshot.forEach((doc37) => {
14077
- templates.push(doc37.data());
14078
- lastVisible = doc37;
14070
+ querySnapshot.forEach((doc38) => {
14071
+ templates.push(doc38.data());
14072
+ lastVisible = doc38;
14073
+ });
14074
+ return {
14075
+ templates,
14076
+ lastDoc: lastVisible
14077
+ };
14078
+ }
14079
+ /**
14080
+ * Get all active templates with optional filters and pagination.
14081
+ * @param options - Options for filtering and pagination.
14082
+ * @returns A promise that resolves to the templates and the last visible document.
14083
+ */
14084
+ async getTemplates(options) {
14085
+ const {
14086
+ pageSize = 20,
14087
+ lastDoc,
14088
+ isUserForm,
14089
+ isRequired,
14090
+ sortingOrder
14091
+ } = options;
14092
+ const constraints = [
14093
+ where25("isActive", "==", true),
14094
+ orderBy13("sortingOrder", "asc"),
14095
+ orderBy13("title", "asc"),
14096
+ limit12(pageSize)
14097
+ ];
14098
+ if (isUserForm !== void 0) {
14099
+ constraints.push(where25("isUserForm", "==", isUserForm));
14100
+ }
14101
+ if (isRequired !== void 0) {
14102
+ constraints.push(where25("isRequired", "==", isRequired));
14103
+ }
14104
+ if (sortingOrder !== void 0) {
14105
+ constraints.push(where25("sortingOrder", "==", sortingOrder));
14106
+ }
14107
+ if (lastDoc) {
14108
+ constraints.push(startAfter10(lastDoc));
14109
+ }
14110
+ const q = query25(this.collectionRef, ...constraints.filter((c) => c));
14111
+ const querySnapshot = await getDocs25(q);
14112
+ const templates = [];
14113
+ let lastVisible = null;
14114
+ querySnapshot.forEach((doc38) => {
14115
+ templates.push(doc38.data());
14116
+ lastVisible = doc38;
14079
14117
  });
14080
14118
  return {
14081
14119
  templates,
14082
14120
  lastDoc: lastVisible
14083
14121
  };
14084
14122
  }
14123
+ /**
14124
+ * Get the total count of active templates with optional filters.
14125
+ * @param options - Options for filtering.
14126
+ * @returns A promise that resolves to the total count of templates.
14127
+ */
14128
+ async getTemplatesCount(options) {
14129
+ const { isUserForm, isRequired, sortingOrder } = options;
14130
+ const constraints = [where25("isActive", "==", true)];
14131
+ if (isUserForm !== void 0) {
14132
+ constraints.push(where25("isUserForm", "==", isUserForm));
14133
+ }
14134
+ if (isRequired !== void 0) {
14135
+ constraints.push(where25("isRequired", "==", isRequired));
14136
+ }
14137
+ if (sortingOrder !== void 0) {
14138
+ constraints.push(where25("sortingOrder", "==", sortingOrder));
14139
+ }
14140
+ const q = query25(this.collectionRef, ...constraints.filter((c) => c));
14141
+ const snapshot = await getCountFromServer(q);
14142
+ return snapshot.data().count;
14143
+ }
14144
+ /**
14145
+ * Get all active templates without pagination for filtering purposes.
14146
+ * @returns A promise that resolves to an array of all active templates.
14147
+ */
14148
+ async getAllActiveTemplates() {
14149
+ const q = query25(
14150
+ this.collectionRef,
14151
+ where25("isActive", "==", true),
14152
+ orderBy13("title", "asc")
14153
+ );
14154
+ const querySnapshot = await getDocs25(q);
14155
+ const templates = [];
14156
+ querySnapshot.forEach((doc38) => {
14157
+ templates.push(doc38.data());
14158
+ });
14159
+ return templates;
14160
+ }
14085
14161
  /**
14086
14162
  * Get templates by tags
14087
14163
  * @param tags - Tags to filter by
@@ -14103,9 +14179,9 @@ var DocumentationTemplateService = class extends BaseService {
14103
14179
  const querySnapshot = await getDocs25(q);
14104
14180
  const templates = [];
14105
14181
  let lastVisible = null;
14106
- querySnapshot.forEach((doc37) => {
14107
- templates.push(doc37.data());
14108
- lastVisible = doc37;
14182
+ querySnapshot.forEach((doc38) => {
14183
+ templates.push(doc38.data());
14184
+ lastVisible = doc38;
14109
14185
  });
14110
14186
  return {
14111
14187
  templates,
@@ -14132,9 +14208,9 @@ var DocumentationTemplateService = class extends BaseService {
14132
14208
  const querySnapshot = await getDocs25(q);
14133
14209
  const templates = [];
14134
14210
  let lastVisible = null;
14135
- querySnapshot.forEach((doc37) => {
14136
- templates.push(doc37.data());
14137
- lastVisible = doc37;
14211
+ querySnapshot.forEach((doc38) => {
14212
+ templates.push(doc38.data());
14213
+ lastVisible = doc38;
14138
14214
  });
14139
14215
  return {
14140
14216
  templates,
@@ -14160,8 +14236,8 @@ var DocumentationTemplateService = class extends BaseService {
14160
14236
  }
14161
14237
  const querySnapshot = await getDocs25(q);
14162
14238
  const templates = [];
14163
- querySnapshot.forEach((doc37) => {
14164
- templates.push(doc37.data());
14239
+ querySnapshot.forEach((doc38) => {
14240
+ templates.push(doc38.data());
14165
14241
  });
14166
14242
  return templates;
14167
14243
  }
@@ -14367,9 +14443,9 @@ var FilledDocumentService = class extends BaseService {
14367
14443
  const querySnapshot = await getDocs26(q);
14368
14444
  const documents = [];
14369
14445
  let lastVisible = null;
14370
- querySnapshot.forEach((doc37) => {
14371
- documents.push(doc37.data());
14372
- lastVisible = doc37;
14446
+ querySnapshot.forEach((doc38) => {
14447
+ documents.push(doc38.data());
14448
+ lastVisible = doc38;
14373
14449
  });
14374
14450
  return {
14375
14451
  documents,
@@ -14591,9 +14667,9 @@ var NotificationService = class extends BaseService {
14591
14667
  orderBy15("notificationTime", "desc")
14592
14668
  );
14593
14669
  const querySnapshot = await getDocs27(q);
14594
- return querySnapshot.docs.map((doc37) => ({
14595
- id: doc37.id,
14596
- ...doc37.data()
14670
+ return querySnapshot.docs.map((doc38) => ({
14671
+ id: doc38.id,
14672
+ ...doc38.data()
14597
14673
  }));
14598
14674
  }
14599
14675
  /**
@@ -14607,9 +14683,9 @@ var NotificationService = class extends BaseService {
14607
14683
  orderBy15("notificationTime", "desc")
14608
14684
  );
14609
14685
  const querySnapshot = await getDocs27(q);
14610
- return querySnapshot.docs.map((doc37) => ({
14611
- id: doc37.id,
14612
- ...doc37.data()
14686
+ return querySnapshot.docs.map((doc38) => ({
14687
+ id: doc38.id,
14688
+ ...doc38.data()
14613
14689
  }));
14614
14690
  }
14615
14691
  /**
@@ -14681,9 +14757,9 @@ var NotificationService = class extends BaseService {
14681
14757
  orderBy15("notificationTime", "desc")
14682
14758
  );
14683
14759
  const querySnapshot = await getDocs27(q);
14684
- return querySnapshot.docs.map((doc37) => ({
14685
- id: doc37.id,
14686
- ...doc37.data()
14760
+ return querySnapshot.docs.map((doc38) => ({
14761
+ id: doc38.id,
14762
+ ...doc38.data()
14687
14763
  }));
14688
14764
  }
14689
14765
  /**
@@ -14696,9 +14772,9 @@ var NotificationService = class extends BaseService {
14696
14772
  orderBy15("notificationTime", "desc")
14697
14773
  );
14698
14774
  const querySnapshot = await getDocs27(q);
14699
- return querySnapshot.docs.map((doc37) => ({
14700
- id: doc37.id,
14701
- ...doc37.data()
14775
+ return querySnapshot.docs.map((doc38) => ({
14776
+ id: doc38.id,
14777
+ ...doc38.data()
14702
14778
  }));
14703
14779
  }
14704
14780
  };
@@ -15002,7 +15078,9 @@ var ProcedureService = class extends BaseService {
15002
15078
  return media;
15003
15079
  }
15004
15080
  if (media instanceof File || media instanceof Blob) {
15005
- console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
15081
+ console.log(
15082
+ `[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
15083
+ );
15006
15084
  const metadata = await this.mediaService.uploadMedia(
15007
15085
  media,
15008
15086
  ownerId,
@@ -15024,7 +15102,11 @@ var ProcedureService = class extends BaseService {
15024
15102
  if (!mediaArray || mediaArray.length === 0) return [];
15025
15103
  const result = [];
15026
15104
  for (const media of mediaArray) {
15027
- const processedUrl = await this.processMedia(media, ownerId, collectionName);
15105
+ const processedUrl = await this.processMedia(
15106
+ media,
15107
+ ownerId,
15108
+ collectionName
15109
+ );
15028
15110
  if (processedUrl) {
15029
15111
  result.push(processedUrl);
15030
15112
  }
@@ -15037,28 +15119,46 @@ var ProcedureService = class extends BaseService {
15037
15119
  * @returns The created procedure
15038
15120
  */
15039
15121
  async createProcedure(data) {
15040
- var _a;
15122
+ var _a, _b, _c;
15041
15123
  const validatedData = createProcedureSchema.parse(data);
15042
15124
  const procedureId = this.generateId();
15043
15125
  const [category, subcategory, technology, product] = await Promise.all([
15044
15126
  this.categoryService.getById(validatedData.categoryId),
15045
- this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
15127
+ this.subcategoryService.getById(
15128
+ validatedData.categoryId,
15129
+ validatedData.subcategoryId
15130
+ ),
15046
15131
  this.technologyService.getById(validatedData.technologyId),
15047
- this.productService.getById(validatedData.technologyId, validatedData.productId)
15132
+ this.productService.getById(
15133
+ validatedData.technologyId,
15134
+ validatedData.productId
15135
+ )
15048
15136
  ]);
15049
15137
  if (!category || !subcategory || !technology || !product) {
15050
15138
  throw new Error("One or more required base entities not found");
15051
15139
  }
15052
- const clinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
15140
+ const clinicRef = doc30(
15141
+ this.db,
15142
+ CLINICS_COLLECTION,
15143
+ validatedData.clinicBranchId
15144
+ );
15053
15145
  const clinicSnapshot = await getDoc32(clinicRef);
15054
15146
  if (!clinicSnapshot.exists()) {
15055
- throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
15147
+ throw new Error(
15148
+ `Clinic with ID ${validatedData.clinicBranchId} not found`
15149
+ );
15056
15150
  }
15057
15151
  const clinic = clinicSnapshot.data();
15058
- const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
15152
+ const practitionerRef = doc30(
15153
+ this.db,
15154
+ PRACTITIONERS_COLLECTION,
15155
+ validatedData.practitionerId
15156
+ );
15059
15157
  const practitionerSnapshot = await getDoc32(practitionerRef);
15060
15158
  if (!practitionerSnapshot.exists()) {
15061
- throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
15159
+ throw new Error(
15160
+ `Practitioner with ID ${validatedData.practitionerId} not found`
15161
+ );
15062
15162
  }
15063
15163
  const practitioner = practitionerSnapshot.data();
15064
15164
  let processedPhotos = [];
@@ -15099,7 +15199,9 @@ var ProcedureService = class extends BaseService {
15099
15199
  product,
15100
15200
  blockingConditions: technology.blockingConditions,
15101
15201
  contraindications: technology.contraindications || [],
15202
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
15102
15203
  treatmentBenefits: technology.benefits,
15204
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
15103
15205
  preRequirements: technology.requirements.pre,
15104
15206
  postRequirements: technology.requirements.post,
15105
15207
  certificationRequirement: technology.certificationRequirement,
@@ -15140,7 +15242,7 @@ var ProcedureService = class extends BaseService {
15140
15242
  * @returns A promise that resolves to an array of the newly created procedures.
15141
15243
  */
15142
15244
  async bulkCreateProcedures(baseData, practitionerIds) {
15143
- var _a;
15245
+ var _a, _b, _c;
15144
15246
  if (!practitionerIds || practitionerIds.length === 0) {
15145
15247
  throw new Error("Practitioner IDs array cannot be empty.");
15146
15248
  }
@@ -15148,16 +15250,24 @@ var ProcedureService = class extends BaseService {
15148
15250
  const validatedData = createProcedureSchema.parse(validationData);
15149
15251
  const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
15150
15252
  this.categoryService.getById(validatedData.categoryId),
15151
- this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
15253
+ this.subcategoryService.getById(
15254
+ validatedData.categoryId,
15255
+ validatedData.subcategoryId
15256
+ ),
15152
15257
  this.technologyService.getById(validatedData.technologyId),
15153
- this.productService.getById(validatedData.technologyId, validatedData.productId),
15258
+ this.productService.getById(
15259
+ validatedData.technologyId,
15260
+ validatedData.productId
15261
+ ),
15154
15262
  getDoc32(doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
15155
15263
  ]);
15156
15264
  if (!category || !subcategory || !technology || !product) {
15157
15265
  throw new Error("One or more required base entities not found");
15158
15266
  }
15159
15267
  if (!clinicSnapshot.exists()) {
15160
- throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
15268
+ throw new Error(
15269
+ `Clinic with ID ${validatedData.clinicBranchId} not found`
15270
+ );
15161
15271
  }
15162
15272
  const clinic = clinicSnapshot.data();
15163
15273
  let processedPhotos = [];
@@ -15177,14 +15287,18 @@ var ProcedureService = class extends BaseService {
15177
15287
  where29(documentId2(), "in", chunk)
15178
15288
  );
15179
15289
  const practitionersSnapshot = await getDocs29(practitionersQuery);
15180
- practitionersSnapshot.docs.forEach((doc37) => {
15181
- practitionersMap.set(doc37.id, doc37.data());
15290
+ practitionersSnapshot.docs.forEach((doc38) => {
15291
+ practitionersMap.set(doc38.id, doc38.data());
15182
15292
  });
15183
15293
  }
15184
15294
  if (practitionersMap.size !== practitionerIds.length) {
15185
15295
  const foundIds = Array.from(practitionersMap.keys());
15186
- const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
15187
- throw new Error(`The following practitioners were not found: ${notFoundIds.join(", ")}`);
15296
+ const notFoundIds = practitionerIds.filter(
15297
+ (id) => !foundIds.includes(id)
15298
+ );
15299
+ throw new Error(
15300
+ `The following practitioners were not found: ${notFoundIds.join(", ")}`
15301
+ );
15188
15302
  }
15189
15303
  const batch = writeBatch6(this.db);
15190
15304
  const createdProcedureIds = [];
@@ -15222,7 +15336,9 @@ var ProcedureService = class extends BaseService {
15222
15336
  product,
15223
15337
  blockingConditions: technology.blockingConditions,
15224
15338
  contraindications: technology.contraindications || [],
15339
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
15225
15340
  treatmentBenefits: technology.benefits,
15341
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
15226
15342
  preRequirements: technology.requirements.pre,
15227
15343
  postRequirements: technology.requirements.post,
15228
15344
  certificationRequirement: technology.certificationRequirement,
@@ -15252,10 +15368,13 @@ var ProcedureService = class extends BaseService {
15252
15368
  const fetchedProcedures = [];
15253
15369
  for (let i = 0; i < createdProcedureIds.length; i += 30) {
15254
15370
  const chunk = createdProcedureIds.slice(i, i + 30);
15255
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), where29(documentId2(), "in", chunk));
15371
+ const q = query29(
15372
+ collection29(this.db, PROCEDURES_COLLECTION),
15373
+ where29(documentId2(), "in", chunk)
15374
+ );
15256
15375
  const snapshot = await getDocs29(q);
15257
- snapshot.forEach((doc37) => {
15258
- fetchedProcedures.push(doc37.data());
15376
+ snapshot.forEach((doc38) => {
15377
+ fetchedProcedures.push(doc38.data());
15259
15378
  });
15260
15379
  }
15261
15380
  return fetchedProcedures;
@@ -15285,7 +15404,7 @@ var ProcedureService = class extends BaseService {
15285
15404
  where29("isActive", "==", true)
15286
15405
  );
15287
15406
  const snapshot = await getDocs29(q);
15288
- return snapshot.docs.map((doc37) => doc37.data());
15407
+ return snapshot.docs.map((doc38) => doc38.data());
15289
15408
  }
15290
15409
  /**
15291
15410
  * Gets all procedures for a practitioner
@@ -15299,7 +15418,7 @@ var ProcedureService = class extends BaseService {
15299
15418
  where29("isActive", "==", true)
15300
15419
  );
15301
15420
  const snapshot = await getDocs29(q);
15302
- return snapshot.docs.map((doc37) => doc37.data());
15421
+ return snapshot.docs.map((doc38) => doc38.data());
15303
15422
  }
15304
15423
  /**
15305
15424
  * Gets all inactive procedures for a practitioner
@@ -15313,7 +15432,7 @@ var ProcedureService = class extends BaseService {
15313
15432
  where29("isActive", "==", false)
15314
15433
  );
15315
15434
  const snapshot = await getDocs29(q);
15316
- return snapshot.docs.map((doc37) => doc37.data());
15435
+ return snapshot.docs.map((doc38) => doc38.data());
15317
15436
  }
15318
15437
  /**
15319
15438
  * Updates a procedure
@@ -15322,7 +15441,7 @@ var ProcedureService = class extends BaseService {
15322
15441
  * @returns The updated procedure
15323
15442
  */
15324
15443
  async updateProcedure(id, data) {
15325
- var _a;
15444
+ var _a, _b, _c;
15326
15445
  const validatedData = updateProcedureSchema.parse(data);
15327
15446
  const procedureRef = doc30(this.db, PROCEDURES_COLLECTION, id);
15328
15447
  const procedureSnapshot = await getDoc32(procedureRef);
@@ -15353,7 +15472,9 @@ var ProcedureService = class extends BaseService {
15353
15472
  );
15354
15473
  const newPractitionerSnap = await getDoc32(newPractitionerRef);
15355
15474
  if (!newPractitionerSnap.exists())
15356
- throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
15475
+ throw new Error(
15476
+ `New Practitioner ${validatedData.practitionerId} not found`
15477
+ );
15357
15478
  newPractitioner = newPractitionerSnap.data();
15358
15479
  updatedProcedureData.doctorInfo = {
15359
15480
  id: newPractitioner.id,
@@ -15367,7 +15488,11 @@ var ProcedureService = class extends BaseService {
15367
15488
  }
15368
15489
  if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
15369
15490
  clinicChanged = true;
15370
- const newClinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
15491
+ const newClinicRef = doc30(
15492
+ this.db,
15493
+ CLINICS_COLLECTION,
15494
+ validatedData.clinicBranchId
15495
+ );
15371
15496
  const newClinicSnap = await getDoc32(newClinicRef);
15372
15497
  if (!newClinicSnap.exists())
15373
15498
  throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
@@ -15386,8 +15511,11 @@ var ProcedureService = class extends BaseService {
15386
15511
  updatedProcedureData.nameLower = validatedData.name.toLowerCase();
15387
15512
  }
15388
15513
  if (validatedData.categoryId) {
15389
- const category = await this.categoryService.getById(validatedData.categoryId);
15390
- if (!category) throw new Error(`Category ${validatedData.categoryId} not found`);
15514
+ const category = await this.categoryService.getById(
15515
+ validatedData.categoryId
15516
+ );
15517
+ if (!category)
15518
+ throw new Error(`Category ${validatedData.categoryId} not found`);
15391
15519
  updatedProcedureData.category = category;
15392
15520
  finalCategoryId = category.id;
15393
15521
  }
@@ -15402,23 +15530,34 @@ var ProcedureService = class extends BaseService {
15402
15530
  );
15403
15531
  updatedProcedureData.subcategory = subcategory;
15404
15532
  } else if (validatedData.subcategoryId) {
15405
- console.warn("Attempted to update subcategory without a valid categoryId");
15533
+ console.warn(
15534
+ "Attempted to update subcategory without a valid categoryId"
15535
+ );
15406
15536
  }
15407
15537
  let finalTechnologyId = existingProcedure.technology.id;
15408
15538
  if (validatedData.technologyId) {
15409
- const technology = await this.technologyService.getById(validatedData.technologyId);
15410
- if (!technology) throw new Error(`Technology ${validatedData.technologyId} not found`);
15539
+ const technology = await this.technologyService.getById(
15540
+ validatedData.technologyId
15541
+ );
15542
+ if (!technology)
15543
+ throw new Error(`Technology ${validatedData.technologyId} not found`);
15411
15544
  updatedProcedureData.technology = technology;
15412
15545
  finalTechnologyId = technology.id;
15413
15546
  updatedProcedureData.blockingConditions = technology.blockingConditions;
15547
+ updatedProcedureData.contraindications = technology.contraindications || [];
15548
+ updatedProcedureData.contraindicationIds = ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [];
15414
15549
  updatedProcedureData.treatmentBenefits = technology.benefits;
15550
+ updatedProcedureData.treatmentBenefitIds = ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [];
15415
15551
  updatedProcedureData.preRequirements = technology.requirements.pre;
15416
15552
  updatedProcedureData.postRequirements = technology.requirements.post;
15417
15553
  updatedProcedureData.certificationRequirement = technology.certificationRequirement;
15418
15554
  updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
15419
15555
  }
15420
15556
  if (validatedData.productId && finalTechnologyId) {
15421
- const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
15557
+ const product = await this.productService.getById(
15558
+ finalTechnologyId,
15559
+ validatedData.productId
15560
+ );
15422
15561
  if (!product)
15423
15562
  throw new Error(
15424
15563
  `Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
@@ -15490,28 +15629,32 @@ var ProcedureService = class extends BaseService {
15490
15629
  const proceduresCollection = collection29(this.db, PROCEDURES_COLLECTION);
15491
15630
  let proceduresQuery = query29(proceduresCollection);
15492
15631
  if (pagination && pagination > 0) {
15493
- const { limit: limit16, startAfter: startAfter14 } = await import("firebase/firestore");
15632
+ const { limit: limit21, startAfter: startAfter19 } = await import("firebase/firestore");
15494
15633
  if (lastDoc) {
15495
15634
  proceduresQuery = query29(
15496
15635
  proceduresCollection,
15497
15636
  orderBy17("name"),
15498
15637
  // Use imported orderBy
15499
- startAfter14(lastDoc),
15500
- limit16(pagination)
15638
+ startAfter19(lastDoc),
15639
+ limit21(pagination)
15501
15640
  );
15502
15641
  } else {
15503
- proceduresQuery = query29(proceduresCollection, orderBy17("name"), limit16(pagination));
15642
+ proceduresQuery = query29(
15643
+ proceduresCollection,
15644
+ orderBy17("name"),
15645
+ limit21(pagination)
15646
+ );
15504
15647
  }
15505
15648
  } else {
15506
15649
  proceduresQuery = query29(proceduresCollection, orderBy17("name"));
15507
15650
  }
15508
15651
  const proceduresSnapshot = await getDocs29(proceduresQuery);
15509
15652
  const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
15510
- const procedures = proceduresSnapshot.docs.map((doc37) => {
15511
- const data = doc37.data();
15653
+ const procedures = proceduresSnapshot.docs.map((doc38) => {
15654
+ const data = doc38.data();
15512
15655
  return {
15513
15656
  ...data,
15514
- id: doc37.id
15657
+ id: doc38.id
15515
15658
  // Ensure ID is present
15516
15659
  };
15517
15660
  });
@@ -15531,7 +15674,7 @@ var ProcedureService = class extends BaseService {
15531
15674
  *
15532
15675
  * @param filters - Various filters to apply
15533
15676
  * @param filters.nameSearch - Optional search text for procedure name
15534
- * @param filters.treatmentBenefits - Optional array of treatment benefits to filter by
15677
+ * @param filters.treatmentBenefitIds - Optional array of treatment benefits to filter by
15535
15678
  * @param filters.procedureFamily - Optional procedure family to filter by
15536
15679
  * @param filters.procedureCategory - Optional procedure category to filter by
15537
15680
  * @param filters.procedureSubcategory - Optional procedure subcategory to filter by
@@ -15549,7 +15692,9 @@ var ProcedureService = class extends BaseService {
15549
15692
  */
15550
15693
  async getProceduresByFilters(filters) {
15551
15694
  try {
15552
- console.log("[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies");
15695
+ console.log(
15696
+ "[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies"
15697
+ );
15553
15698
  if (filters.location && filters.radiusInKm) {
15554
15699
  console.log("[PROCEDURE_SERVICE] Executing geo query:", {
15555
15700
  location: filters.location,
@@ -15557,7 +15702,10 @@ var ProcedureService = class extends BaseService {
15557
15702
  serviceName: "ProcedureService"
15558
15703
  });
15559
15704
  if (!filters.location.latitude || !filters.location.longitude) {
15560
- console.warn("[PROCEDURE_SERVICE] Invalid location data:", filters.location);
15705
+ console.warn(
15706
+ "[PROCEDURE_SERVICE] Invalid location data:",
15707
+ filters.location
15708
+ );
15561
15709
  filters.location = void 0;
15562
15710
  filters.radiusInKm = void 0;
15563
15711
  }
@@ -15577,13 +15725,19 @@ var ProcedureService = class extends BaseService {
15577
15725
  constraints.push(where29("family", "==", filters.procedureFamily));
15578
15726
  }
15579
15727
  if (filters.procedureCategory) {
15580
- constraints.push(where29("category.id", "==", filters.procedureCategory));
15728
+ constraints.push(
15729
+ where29("category.id", "==", filters.procedureCategory)
15730
+ );
15581
15731
  }
15582
15732
  if (filters.procedureSubcategory) {
15583
- constraints.push(where29("subcategory.id", "==", filters.procedureSubcategory));
15733
+ constraints.push(
15734
+ where29("subcategory.id", "==", filters.procedureSubcategory)
15735
+ );
15584
15736
  }
15585
15737
  if (filters.procedureTechnology) {
15586
- constraints.push(where29("technology.id", "==", filters.procedureTechnology));
15738
+ constraints.push(
15739
+ where29("technology.id", "==", filters.procedureTechnology)
15740
+ );
15587
15741
  }
15588
15742
  if (filters.minPrice !== void 0) {
15589
15743
  constraints.push(where29("price", ">=", filters.minPrice));
@@ -15592,20 +15746,32 @@ var ProcedureService = class extends BaseService {
15592
15746
  constraints.push(where29("price", "<=", filters.maxPrice));
15593
15747
  }
15594
15748
  if (filters.minRating !== void 0) {
15595
- constraints.push(where29("reviewInfo.averageRating", ">=", filters.minRating));
15749
+ constraints.push(
15750
+ where29("reviewInfo.averageRating", ">=", filters.minRating)
15751
+ );
15596
15752
  }
15597
15753
  if (filters.maxRating !== void 0) {
15598
- constraints.push(where29("reviewInfo.averageRating", "<=", filters.maxRating));
15754
+ constraints.push(
15755
+ where29("reviewInfo.averageRating", "<=", filters.maxRating)
15756
+ );
15599
15757
  }
15600
15758
  if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
15601
- const benefitsToMatch = filters.treatmentBenefits;
15602
- constraints.push(where29("treatmentBenefits", "array-contains-any", benefitsToMatch));
15759
+ const benefitIdsToMatch = filters.treatmentBenefits;
15760
+ constraints.push(
15761
+ where29(
15762
+ "treatmentBenefitIds",
15763
+ "array-contains-any",
15764
+ benefitIdsToMatch
15765
+ )
15766
+ );
15603
15767
  }
15604
15768
  return constraints;
15605
15769
  };
15606
15770
  if (filters.nameSearch && filters.nameSearch.trim()) {
15607
15771
  try {
15608
- console.log("[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search");
15772
+ console.log(
15773
+ "[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search"
15774
+ );
15609
15775
  const searchTerm = filters.nameSearch.trim().toLowerCase();
15610
15776
  const constraints = getBaseConstraints();
15611
15777
  constraints.push(where29("nameLower", ">=", searchTerm));
@@ -15621,13 +15787,18 @@ var ProcedureService = class extends BaseService {
15621
15787
  }
15622
15788
  }
15623
15789
  constraints.push(limit15(filters.pagination || 10));
15624
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15790
+ const q = query29(
15791
+ collection29(this.db, PROCEDURES_COLLECTION),
15792
+ ...constraints
15793
+ );
15625
15794
  const querySnapshot = await getDocs29(q);
15626
15795
  const procedures = querySnapshot.docs.map(
15627
- (doc37) => ({ ...doc37.data(), id: doc37.id })
15796
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
15628
15797
  );
15629
15798
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15630
- console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
15799
+ console.log(
15800
+ `[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`
15801
+ );
15631
15802
  if (procedures.length < (filters.pagination || 10)) {
15632
15803
  return { procedures, lastDoc: null };
15633
15804
  }
@@ -15638,7 +15809,9 @@ var ProcedureService = class extends BaseService {
15638
15809
  }
15639
15810
  if (filters.nameSearch && filters.nameSearch.trim()) {
15640
15811
  try {
15641
- console.log("[PROCEDURE_SERVICE] Strategy 2: Trying name field search");
15812
+ console.log(
15813
+ "[PROCEDURE_SERVICE] Strategy 2: Trying name field search"
15814
+ );
15642
15815
  const searchTerm = filters.nameSearch.trim().toLowerCase();
15643
15816
  const constraints = getBaseConstraints();
15644
15817
  constraints.push(where29("name", ">=", searchTerm));
@@ -15654,13 +15827,18 @@ var ProcedureService = class extends BaseService {
15654
15827
  }
15655
15828
  }
15656
15829
  constraints.push(limit15(filters.pagination || 10));
15657
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15830
+ const q = query29(
15831
+ collection29(this.db, PROCEDURES_COLLECTION),
15832
+ ...constraints
15833
+ );
15658
15834
  const querySnapshot = await getDocs29(q);
15659
15835
  const procedures = querySnapshot.docs.map(
15660
- (doc37) => ({ ...doc37.data(), id: doc37.id })
15836
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
15661
15837
  );
15662
15838
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15663
- console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
15839
+ console.log(
15840
+ `[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`
15841
+ );
15664
15842
  if (procedures.length < (filters.pagination || 10)) {
15665
15843
  return { procedures, lastDoc: null };
15666
15844
  }
@@ -15685,14 +15863,19 @@ var ProcedureService = class extends BaseService {
15685
15863
  }
15686
15864
  }
15687
15865
  constraints.push(limit15(filters.pagination || 10));
15688
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15866
+ const q = query29(
15867
+ collection29(this.db, PROCEDURES_COLLECTION),
15868
+ ...constraints
15869
+ );
15689
15870
  const querySnapshot = await getDocs29(q);
15690
15871
  let procedures = querySnapshot.docs.map(
15691
- (doc37) => ({ ...doc37.data(), id: doc37.id })
15872
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
15692
15873
  );
15693
15874
  procedures = this.applyInMemoryFilters(procedures, filters);
15694
15875
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15695
- console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
15876
+ console.log(
15877
+ `[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`
15878
+ );
15696
15879
  if (procedures.length < (filters.pagination || 10)) {
15697
15880
  return { procedures, lastDoc: null };
15698
15881
  }
@@ -15707,14 +15890,19 @@ var ProcedureService = class extends BaseService {
15707
15890
  orderBy17("createdAt", "desc"),
15708
15891
  limit15(filters.pagination || 10)
15709
15892
  ];
15710
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15893
+ const q = query29(
15894
+ collection29(this.db, PROCEDURES_COLLECTION),
15895
+ ...constraints
15896
+ );
15711
15897
  const querySnapshot = await getDocs29(q);
15712
15898
  let procedures = querySnapshot.docs.map(
15713
- (doc37) => ({ ...doc37.data(), id: doc37.id })
15899
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
15714
15900
  );
15715
15901
  procedures = this.applyInMemoryFilters(procedures, filters);
15716
15902
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15717
- console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
15903
+ console.log(
15904
+ `[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`
15905
+ );
15718
15906
  if (procedures.length < (filters.pagination || 10)) {
15719
15907
  return { procedures, lastDoc: null };
15720
15908
  }
@@ -15722,7 +15910,9 @@ var ProcedureService = class extends BaseService {
15722
15910
  } catch (error) {
15723
15911
  console.log("[PROCEDURE_SERVICE] Strategy 4 failed:", error);
15724
15912
  }
15725
- console.log("[PROCEDURE_SERVICE] All strategies failed, returning empty result");
15913
+ console.log(
15914
+ "[PROCEDURE_SERVICE] All strategies failed, returning empty result"
15915
+ );
15726
15916
  return { procedures: [], lastDoc: null };
15727
15917
  } catch (error) {
15728
15918
  console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
@@ -15742,13 +15932,17 @@ var ProcedureService = class extends BaseService {
15742
15932
  const nameLower = procedure.nameLower || "";
15743
15933
  return name.includes(searchTerm) || nameLower.includes(searchTerm);
15744
15934
  });
15745
- console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`);
15935
+ console.log(
15936
+ `[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`
15937
+ );
15746
15938
  }
15747
15939
  if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
15748
15940
  filteredProcedures = filteredProcedures.filter((procedure) => {
15749
15941
  const price = procedure.price || 0;
15750
- if (filters.minPrice !== void 0 && price < filters.minPrice) return false;
15751
- if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
15942
+ if (filters.minPrice !== void 0 && price < filters.minPrice)
15943
+ return false;
15944
+ if (filters.maxPrice !== void 0 && price > filters.maxPrice)
15945
+ return false;
15752
15946
  return true;
15753
15947
  });
15754
15948
  console.log(
@@ -15759,8 +15953,10 @@ var ProcedureService = class extends BaseService {
15759
15953
  filteredProcedures = filteredProcedures.filter((procedure) => {
15760
15954
  var _a;
15761
15955
  const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
15762
- if (filters.minRating !== void 0 && rating < filters.minRating) return false;
15763
- if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
15956
+ if (filters.minRating !== void 0 && rating < filters.minRating)
15957
+ return false;
15958
+ if (filters.maxRating !== void 0 && rating > filters.maxRating)
15959
+ return false;
15764
15960
  return true;
15765
15961
  });
15766
15962
  console.log(
@@ -15768,10 +15964,12 @@ var ProcedureService = class extends BaseService {
15768
15964
  );
15769
15965
  }
15770
15966
  if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
15771
- const benefitsToMatch = filters.treatmentBenefits;
15967
+ const benefitIdsToMatch = filters.treatmentBenefits;
15772
15968
  filteredProcedures = filteredProcedures.filter((procedure) => {
15773
- const procedureBenefits = procedure.treatmentBenefits || [];
15774
- return benefitsToMatch.some((benefit) => procedureBenefits.includes(benefit));
15969
+ const procedureBenefitIds = procedure.treatmentBenefitIds || [];
15970
+ return benefitIdsToMatch.some(
15971
+ (benefitId) => procedureBenefitIds.includes(benefitId)
15972
+ );
15775
15973
  });
15776
15974
  console.log(
15777
15975
  `[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
@@ -15834,8 +16032,12 @@ var ProcedureService = class extends BaseService {
15834
16032
  procedure.distance = distance;
15835
16033
  return distance <= radiusInKm;
15836
16034
  });
15837
- console.log(`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`);
15838
- filteredProcedures.sort((a, b) => (a.distance || 0) - (b.distance || 0));
16035
+ console.log(
16036
+ `[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`
16037
+ );
16038
+ filteredProcedures.sort(
16039
+ (a, b) => (a.distance || 0) - (b.distance || 0)
16040
+ );
15839
16041
  }
15840
16042
  return filteredProcedures;
15841
16043
  }
@@ -15847,19 +16049,30 @@ var ProcedureService = class extends BaseService {
15847
16049
  if (!location || !radiusInKm) {
15848
16050
  return Promise.resolve({ procedures: [], lastDoc: null });
15849
16051
  }
15850
- const bounds = geohashQueryBounds5([location.latitude, location.longitude], radiusInKm * 1e3);
16052
+ const bounds = geohashQueryBounds5(
16053
+ [location.latitude, location.longitude],
16054
+ radiusInKm * 1e3
16055
+ );
15851
16056
  const fetches = bounds.map((b) => {
15852
16057
  const constraints = [
15853
16058
  where29("clinicInfo.location.geohash", ">=", b[0]),
15854
16059
  where29("clinicInfo.location.geohash", "<=", b[1]),
15855
- where29("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
16060
+ where29(
16061
+ "isActive",
16062
+ "==",
16063
+ filters.isActive !== void 0 ? filters.isActive : true
16064
+ )
15856
16065
  ];
15857
- return getDocs29(query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints));
16066
+ return getDocs29(
16067
+ query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints)
16068
+ );
15858
16069
  });
15859
16070
  return Promise.all(fetches).then((snaps) => {
15860
16071
  const collected = [];
15861
16072
  snaps.forEach((snap) => {
15862
- snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
16073
+ snap.docs.forEach(
16074
+ (d) => collected.push({ ...d.data(), id: d.id })
16075
+ );
15863
16076
  });
15864
16077
  const uniqueMap = /* @__PURE__ */ new Map();
15865
16078
  for (const p of collected) {
@@ -15870,7 +16083,9 @@ var ProcedureService = class extends BaseService {
15870
16083
  const pageSize = filters.pagination || 10;
15871
16084
  let startIndex = 0;
15872
16085
  if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
15873
- const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
16086
+ const idx = procedures.findIndex(
16087
+ (p) => p.id === filters.lastDoc.id
16088
+ );
15874
16089
  if (idx >= 0) startIndex = idx + 1;
15875
16090
  }
15876
16091
  const page = procedures.slice(startIndex, startIndex + pageSize);
@@ -15895,7 +16110,7 @@ var ProcedureService = class extends BaseService {
15895
16110
  * @returns The created procedure
15896
16111
  */
15897
16112
  async createConsultationProcedure(data) {
15898
- var _a;
16113
+ var _a, _b, _c;
15899
16114
  const procedureId = this.generateId();
15900
16115
  const [category, subcategory, technology] = await Promise.all([
15901
16116
  this.categoryService.getById(data.categoryId),
@@ -15911,7 +16126,11 @@ var ProcedureService = class extends BaseService {
15911
16126
  throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
15912
16127
  }
15913
16128
  const clinic = clinicSnapshot.data();
15914
- const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
16129
+ const practitionerRef = doc30(
16130
+ this.db,
16131
+ PRACTITIONERS_COLLECTION,
16132
+ data.practitionerId
16133
+ );
15915
16134
  const practitionerSnapshot = await getDoc32(practitionerRef);
15916
16135
  if (!practitionerSnapshot.exists()) {
15917
16136
  throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
@@ -15919,7 +16138,11 @@ var ProcedureService = class extends BaseService {
15919
16138
  const practitioner = practitionerSnapshot.data();
15920
16139
  let processedPhotos = [];
15921
16140
  if (data.photos && data.photos.length > 0) {
15922
- processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
16141
+ processedPhotos = await this.processMediaArray(
16142
+ data.photos,
16143
+ procedureId,
16144
+ "procedure-photos"
16145
+ );
15923
16146
  }
15924
16147
  const clinicInfo = {
15925
16148
  id: clinicSnapshot.id,
@@ -15945,6 +16168,8 @@ var ProcedureService = class extends BaseService {
15945
16168
  brandName: "Consultation",
15946
16169
  technologyId: data.technologyId,
15947
16170
  technologyName: technology.name,
16171
+ categoryId: technology.categoryId,
16172
+ subcategoryId: technology.subcategoryId,
15948
16173
  isActive: true,
15949
16174
  createdAt: /* @__PURE__ */ new Date(),
15950
16175
  updatedAt: /* @__PURE__ */ new Date()
@@ -15961,7 +16186,9 @@ var ProcedureService = class extends BaseService {
15961
16186
  // Use placeholder product
15962
16187
  blockingConditions: technology.blockingConditions,
15963
16188
  contraindications: technology.contraindications || [],
16189
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
15964
16190
  treatmentBenefits: technology.benefits,
16191
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
15965
16192
  preRequirements: technology.requirements.pre,
15966
16193
  postRequirements: technology.requirements.post,
15967
16194
  certificationRequirement: technology.certificationRequirement,
@@ -15997,11 +16224,11 @@ var ProcedureService = class extends BaseService {
15997
16224
  async getProceduresForMap() {
15998
16225
  const proceduresRef = collection29(this.db, PROCEDURES_COLLECTION);
15999
16226
  const snapshot = await getDocs29(proceduresRef);
16000
- const proceduresForMap = snapshot.docs.map((doc37) => {
16227
+ const proceduresForMap = snapshot.docs.map((doc38) => {
16001
16228
  var _a, _b, _c, _d, _e, _f, _g, _h;
16002
- const data = doc37.data();
16229
+ const data = doc38.data();
16003
16230
  return {
16004
- id: doc37.id,
16231
+ id: doc38.id,
16005
16232
  name: data.name,
16006
16233
  clinicId: (_a = data.clinicInfo) == null ? void 0 : _a.id,
16007
16234
  clinicName: (_b = data.clinicInfo) == null ? void 0 : _b.name,
@@ -16143,7 +16370,7 @@ var ReviewService = class extends BaseService {
16143
16370
  where30("patientId", "==", patientId)
16144
16371
  );
16145
16372
  const snapshot = await getDocs30(q);
16146
- return snapshot.docs.map((doc37) => doc37.data());
16373
+ return snapshot.docs.map((doc38) => doc38.data());
16147
16374
  }
16148
16375
  /**
16149
16376
  * Gets all reviews for a specific clinic
@@ -16156,7 +16383,7 @@ var ReviewService = class extends BaseService {
16156
16383
  where30("clinicReview.clinicId", "==", clinicId)
16157
16384
  );
16158
16385
  const snapshot = await getDocs30(q);
16159
- return snapshot.docs.map((doc37) => doc37.data());
16386
+ return snapshot.docs.map((doc38) => doc38.data());
16160
16387
  }
16161
16388
  /**
16162
16389
  * Gets all reviews for a specific practitioner
@@ -16169,7 +16396,7 @@ var ReviewService = class extends BaseService {
16169
16396
  where30("practitionerReview.practitionerId", "==", practitionerId)
16170
16397
  );
16171
16398
  const snapshot = await getDocs30(q);
16172
- return snapshot.docs.map((doc37) => doc37.data());
16399
+ return snapshot.docs.map((doc38) => doc38.data());
16173
16400
  }
16174
16401
  /**
16175
16402
  * Gets all reviews for a specific procedure
@@ -16182,7 +16409,7 @@ var ReviewService = class extends BaseService {
16182
16409
  where30("procedureReview.procedureId", "==", procedureId)
16183
16410
  );
16184
16411
  const snapshot = await getDocs30(q);
16185
- return snapshot.docs.map((doc37) => doc37.data());
16412
+ return snapshot.docs.map((doc38) => doc38.data());
16186
16413
  }
16187
16414
  /**
16188
16415
  * Gets all reviews for a specific appointment
@@ -16288,7 +16515,11 @@ import {
16288
16515
  getDocs as getDocs31,
16289
16516
  query as query31,
16290
16517
  updateDoc as updateDoc30,
16291
- where as where31
16518
+ where as where31,
16519
+ limit as limit16,
16520
+ orderBy as orderBy18,
16521
+ startAfter as startAfter14,
16522
+ getCountFromServer as getCountFromServer2
16292
16523
  } from "firebase/firestore";
16293
16524
 
16294
16525
  // src/backoffice/types/brand.types.ts
@@ -16309,6 +16540,7 @@ var BrandService = class extends BaseService {
16309
16540
  const now = /* @__PURE__ */ new Date();
16310
16541
  const newBrand = {
16311
16542
  ...brand,
16543
+ name_lowercase: brand.name.toLowerCase(),
16312
16544
  createdAt: now,
16313
16545
  updatedAt: now,
16314
16546
  isActive: true
@@ -16317,15 +16549,69 @@ var BrandService = class extends BaseService {
16317
16549
  return { id: docRef.id, ...newBrand };
16318
16550
  }
16319
16551
  /**
16320
- * Gets all active brands
16552
+ * Gets a paginated list of active brands, optionally filtered by name.
16553
+ * @param rowsPerPage - The number of brands to fetch.
16554
+ * @param searchTerm - An optional string to filter brand names by (starts-with search).
16555
+ * @param lastVisible - An optional document snapshot to use as a cursor for pagination.
16556
+ */
16557
+ async getAll(rowsPerPage, searchTerm, lastVisible) {
16558
+ const constraints = [
16559
+ where31("isActive", "==", true),
16560
+ orderBy18("name_lowercase")
16561
+ ];
16562
+ if (searchTerm) {
16563
+ const lowercasedSearchTerm = searchTerm.toLowerCase();
16564
+ constraints.push(where31("name_lowercase", ">=", lowercasedSearchTerm));
16565
+ constraints.push(
16566
+ where31("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
16567
+ );
16568
+ }
16569
+ if (lastVisible) {
16570
+ constraints.push(startAfter14(lastVisible));
16571
+ }
16572
+ constraints.push(limit16(rowsPerPage));
16573
+ const q = query31(this.getBrandsRef(), ...constraints);
16574
+ const snapshot = await getDocs31(q);
16575
+ const brands = snapshot.docs.map(
16576
+ (doc38) => ({
16577
+ id: doc38.id,
16578
+ ...doc38.data()
16579
+ })
16580
+ );
16581
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
16582
+ return { brands, lastVisible: newLastVisible };
16583
+ }
16584
+ /**
16585
+ * Gets the total count of active brands, optionally filtered by name.
16586
+ * @param searchTerm - An optional string to filter brand names by (starts-with search).
16587
+ */
16588
+ async getBrandsCount(searchTerm) {
16589
+ const constraints = [where31("isActive", "==", true)];
16590
+ if (searchTerm) {
16591
+ const lowercasedSearchTerm = searchTerm.toLowerCase();
16592
+ constraints.push(where31("name_lowercase", ">=", lowercasedSearchTerm));
16593
+ constraints.push(
16594
+ where31("name_lowercase", "<=", lowercasedSearchTerm + "\uF8FF")
16595
+ );
16596
+ }
16597
+ const q = query31(this.getBrandsRef(), ...constraints);
16598
+ const snapshot = await getCountFromServer2(q);
16599
+ return snapshot.data().count;
16600
+ }
16601
+ /**
16602
+ * Gets all active brands for filter dropdowns (not paginated).
16321
16603
  */
16322
- async getAll() {
16323
- const q = query31(this.getBrandsRef(), where31("isActive", "==", true));
16604
+ async getAllForFilter() {
16605
+ const q = query31(
16606
+ this.getBrandsRef(),
16607
+ where31("isActive", "==", true),
16608
+ orderBy18("name")
16609
+ );
16324
16610
  const snapshot = await getDocs31(q);
16325
16611
  return snapshot.docs.map(
16326
- (doc37) => ({
16327
- id: doc37.id,
16328
- ...doc37.data()
16612
+ (doc38) => ({
16613
+ id: doc38.id,
16614
+ ...doc38.data()
16329
16615
  })
16330
16616
  );
16331
16617
  }
@@ -16337,6 +16623,9 @@ var BrandService = class extends BaseService {
16337
16623
  ...brand,
16338
16624
  updatedAt: /* @__PURE__ */ new Date()
16339
16625
  };
16626
+ if (brand.name) {
16627
+ updateData.name_lowercase = brand.name.toLowerCase();
16628
+ }
16340
16629
  const docRef = doc32(this.getBrandsRef(), brandId);
16341
16630
  await updateDoc30(docRef, updateData);
16342
16631
  return this.getById(brandId);
@@ -16368,9 +16657,13 @@ import {
16368
16657
  addDoc as addDoc4,
16369
16658
  collection as collection32,
16370
16659
  doc as doc33,
16660
+ getCountFromServer as getCountFromServer3,
16371
16661
  getDoc as getDoc35,
16372
16662
  getDocs as getDocs32,
16663
+ limit as limit17,
16664
+ orderBy as orderBy19,
16373
16665
  query as query32,
16666
+ startAfter as startAfter15,
16374
16667
  updateDoc as updateDoc31,
16375
16668
  where as where32
16376
16669
  } from "firebase/firestore";
@@ -16403,37 +16696,87 @@ var CategoryService = class extends BaseService {
16403
16696
  return { id: docRef.id, ...newCategory };
16404
16697
  }
16405
16698
  /**
16406
- * Vraća sve aktivne kategorije
16407
- * @returns Lista aktivnih kategorija
16699
+ * Returns counts of categories for each family.
16700
+ * @param active - Whether to count active or inactive categories.
16701
+ * @returns A record mapping family to category count.
16702
+ */
16703
+ async getCategoryCounts(active = true) {
16704
+ const counts = {};
16705
+ const families = Object.values(ProcedureFamily);
16706
+ for (const family of families) {
16707
+ const q = query32(
16708
+ this.categoriesRef,
16709
+ where32("family", "==", family),
16710
+ where32("isActive", "==", active)
16711
+ );
16712
+ const snapshot = await getCountFromServer3(q);
16713
+ counts[family] = snapshot.data().count;
16714
+ }
16715
+ return counts;
16716
+ }
16717
+ /**
16718
+ * Vraća sve kategorije za potrebe filtera (bez paginacije)
16719
+ * @returns Lista svih aktivnih kategorija
16408
16720
  */
16409
- async getAll() {
16721
+ async getAllForFilter() {
16410
16722
  const q = query32(this.categoriesRef, where32("isActive", "==", true));
16411
16723
  const snapshot = await getDocs32(q);
16412
16724
  return snapshot.docs.map(
16413
- (doc37) => ({
16414
- id: doc37.id,
16415
- ...doc37.data()
16725
+ (doc38) => ({
16726
+ id: doc38.id,
16727
+ ...doc38.data()
16728
+ })
16729
+ );
16730
+ }
16731
+ /**
16732
+ * Vraća sve kategorije sa paginacijom
16733
+ * @param options - Pagination and filter options
16734
+ * @returns Lista kategorija i poslednji vidljiv dokument
16735
+ */
16736
+ async getAll(options = {}) {
16737
+ const { active = true, limit: queryLimit = 10, lastVisible } = options;
16738
+ const constraints = [
16739
+ where32("isActive", "==", active),
16740
+ orderBy19("name"),
16741
+ queryLimit ? limit17(queryLimit) : void 0,
16742
+ lastVisible ? startAfter15(lastVisible) : void 0
16743
+ ].filter((c) => !!c);
16744
+ const q = query32(this.categoriesRef, ...constraints);
16745
+ const snapshot = await getDocs32(q);
16746
+ const categories = snapshot.docs.map(
16747
+ (doc38) => ({
16748
+ id: doc38.id,
16749
+ ...doc38.data()
16416
16750
  })
16417
16751
  );
16752
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
16753
+ return { categories, lastVisible: newLastVisible };
16418
16754
  }
16419
16755
  /**
16420
- * Vraća sve aktivne kategorije za određenu familiju procedura
16756
+ * Vraća sve aktivne kategorije za određenu familiju procedura sa paginacijom
16421
16757
  * @param family - Familija procedura (aesthetics/surgery)
16758
+ * @param options - Pagination options
16422
16759
  * @returns Lista kategorija koje pripadaju traženoj familiji
16423
16760
  */
16424
- async getAllByFamily(family) {
16425
- const q = query32(
16426
- this.categoriesRef,
16761
+ async getAllByFamily(family, options = {}) {
16762
+ const { active = true, limit: queryLimit = 10, lastVisible } = options;
16763
+ const constraints = [
16427
16764
  where32("family", "==", family),
16428
- where32("isActive", "==", true)
16429
- );
16765
+ where32("isActive", "==", active),
16766
+ orderBy19("name"),
16767
+ queryLimit ? limit17(queryLimit) : void 0,
16768
+ lastVisible ? startAfter15(lastVisible) : void 0
16769
+ ].filter((c) => !!c);
16770
+ const q = query32(this.categoriesRef, ...constraints);
16430
16771
  const snapshot = await getDocs32(q);
16431
- return snapshot.docs.map(
16432
- (doc37) => ({
16433
- id: doc37.id,
16434
- ...doc37.data()
16772
+ const categories = snapshot.docs.map(
16773
+ (doc38) => ({
16774
+ id: doc38.id,
16775
+ ...doc38.data()
16435
16776
  })
16436
16777
  );
16778
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
16779
+ return { categories, lastVisible: newLastVisible };
16437
16780
  }
16438
16781
  /**
16439
16782
  * Ažurira postojeću kategoriju
@@ -16457,6 +16800,13 @@ var CategoryService = class extends BaseService {
16457
16800
  async delete(id) {
16458
16801
  await this.update(id, { isActive: false });
16459
16802
  }
16803
+ /**
16804
+ * Reactivates a category by setting its isActive flag to true.
16805
+ * @param id - The ID of the category to reactivate.
16806
+ */
16807
+ async reactivate(id) {
16808
+ await this.update(id, { isActive: true });
16809
+ }
16460
16810
  /**
16461
16811
  * Vraća kategoriju po ID-u
16462
16812
  * @param id - ID tražene kategorije
@@ -16477,10 +16827,17 @@ var CategoryService = class extends BaseService {
16477
16827
  import {
16478
16828
  addDoc as addDoc5,
16479
16829
  collection as collection33,
16830
+ collectionGroup as collectionGroup2,
16831
+ deleteDoc as deleteDoc20,
16480
16832
  doc as doc34,
16833
+ getCountFromServer as getCountFromServer4,
16481
16834
  getDoc as getDoc36,
16482
16835
  getDocs as getDocs33,
16836
+ limit as limit18,
16837
+ orderBy as orderBy20,
16483
16838
  query as query33,
16839
+ setDoc as setDoc28,
16840
+ startAfter as startAfter16,
16484
16841
  updateDoc as updateDoc32,
16485
16842
  where as where33
16486
16843
  } from "firebase/firestore";
@@ -16524,20 +16881,110 @@ var SubcategoryService = class extends BaseService {
16524
16881
  return { id: docRef.id, ...newSubcategory };
16525
16882
  }
16526
16883
  /**
16527
- * Vraća sve aktivne podkategorije za određenu kategoriju
16884
+ * Returns counts of subcategories for all categories.
16885
+ * @param active - Whether to count active or inactive subcategories.
16886
+ * @returns A record mapping category ID to subcategory count.
16887
+ */
16888
+ async getSubcategoryCounts(active = true) {
16889
+ const categoriesRef = collection33(this.db, CATEGORIES_COLLECTION);
16890
+ const categoriesSnapshot = await getDocs33(categoriesRef);
16891
+ const counts = {};
16892
+ for (const categoryDoc of categoriesSnapshot.docs) {
16893
+ const categoryId = categoryDoc.id;
16894
+ const subcategoriesRef = this.getSubcategoriesRef(categoryId);
16895
+ const q = query33(subcategoriesRef, where33("isActive", "==", active));
16896
+ const snapshot = await getCountFromServer4(q);
16897
+ counts[categoryId] = snapshot.data().count;
16898
+ }
16899
+ return counts;
16900
+ }
16901
+ /**
16902
+ * Vraća sve aktivne podkategorije za određenu kategoriju sa paginacijom
16528
16903
  * @param categoryId - ID kategorije čije podkategorije tražimo
16529
- * @returns Lista aktivnih podkategorija
16904
+ * @param options - Pagination options
16905
+ * @returns Lista aktivnih podkategorija i poslednji vidljiv dokument
16906
+ */
16907
+ async getAllByCategoryId(categoryId, options = {}) {
16908
+ const { active = true, limit: queryLimit = 10, lastVisible } = options;
16909
+ const constraints = [
16910
+ where33("isActive", "==", active),
16911
+ orderBy20("name"),
16912
+ queryLimit ? limit18(queryLimit) : void 0,
16913
+ lastVisible ? startAfter16(lastVisible) : void 0
16914
+ ].filter((c) => !!c);
16915
+ const q = query33(this.getSubcategoriesRef(categoryId), ...constraints);
16916
+ const querySnapshot = await getDocs33(q);
16917
+ const subcategories = querySnapshot.docs.map(
16918
+ (doc38) => ({
16919
+ id: doc38.id,
16920
+ ...doc38.data()
16921
+ })
16922
+ );
16923
+ const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
16924
+ return { subcategories, lastVisible: newLastVisible };
16925
+ }
16926
+ /**
16927
+ * Vraća sve podkategorije sa paginacijom koristeći collection group query.
16928
+ * NOTE: This query requires a composite index in Firestore on the 'subcategories' collection group.
16929
+ * The index should be on 'isActive' (ascending) and 'name' (ascending).
16930
+ * Firestore will provide a link to create this index in the console error if it's missing.
16931
+ * @param options - Pagination options
16932
+ * @returns Lista podkategorija i poslednji vidljiv dokument
16530
16933
  */
16531
- async getAllByCategoryId(categoryId) {
16934
+ async getAll(options = {}) {
16935
+ const { active = true, limit: queryLimit = 10, lastVisible } = options;
16936
+ const constraints = [
16937
+ where33("isActive", "==", active),
16938
+ orderBy20("name"),
16939
+ queryLimit ? limit18(queryLimit) : void 0,
16940
+ lastVisible ? startAfter16(lastVisible) : void 0
16941
+ ].filter((c) => !!c);
16942
+ const q = query33(
16943
+ collectionGroup2(this.db, SUBCATEGORIES_COLLECTION),
16944
+ ...constraints
16945
+ );
16946
+ const querySnapshot = await getDocs33(q);
16947
+ const subcategories = querySnapshot.docs.map(
16948
+ (doc38) => ({
16949
+ id: doc38.id,
16950
+ ...doc38.data()
16951
+ })
16952
+ );
16953
+ const newLastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
16954
+ return { subcategories, lastVisible: newLastVisible };
16955
+ }
16956
+ /**
16957
+ * Vraća sve subkategorije za određenu kategoriju za potrebe filtera (bez paginacije)
16958
+ * @param categoryId - ID kategorije čije subkategorije tražimo
16959
+ * @returns Lista svih aktivnih subkategorija
16960
+ */
16961
+ async getAllForFilterByCategoryId(categoryId) {
16532
16962
  const q = query33(
16533
16963
  this.getSubcategoriesRef(categoryId),
16534
16964
  where33("isActive", "==", true)
16535
16965
  );
16536
- const snapshot = await getDocs33(q);
16537
- return snapshot.docs.map(
16538
- (doc37) => ({
16539
- id: doc37.id,
16540
- ...doc37.data()
16966
+ const querySnapshot = await getDocs33(q);
16967
+ return querySnapshot.docs.map(
16968
+ (doc38) => ({
16969
+ id: doc38.id,
16970
+ ...doc38.data()
16971
+ })
16972
+ );
16973
+ }
16974
+ /**
16975
+ * Vraća sve subkategorije za potrebe filtera (bez paginacije)
16976
+ * @returns Lista svih aktivnih subkategorija
16977
+ */
16978
+ async getAllForFilter() {
16979
+ const q = query33(
16980
+ collectionGroup2(this.db, SUBCATEGORIES_COLLECTION),
16981
+ where33("isActive", "==", true)
16982
+ );
16983
+ const querySnapshot = await getDocs33(q);
16984
+ return querySnapshot.docs.map(
16985
+ (doc38) => ({
16986
+ id: doc38.id,
16987
+ ...doc38.data()
16541
16988
  })
16542
16989
  );
16543
16990
  }
@@ -16549,13 +16996,42 @@ var SubcategoryService = class extends BaseService {
16549
16996
  * @returns Ažurirana podkategorija
16550
16997
  */
16551
16998
  async update(categoryId, subcategoryId, subcategory) {
16552
- const updateData = {
16553
- ...subcategory,
16554
- updatedAt: /* @__PURE__ */ new Date()
16555
- };
16556
- const docRef = doc34(this.getSubcategoriesRef(categoryId), subcategoryId);
16557
- await updateDoc32(docRef, updateData);
16558
- return this.getById(categoryId, subcategoryId);
16999
+ const newCategoryId = subcategory.categoryId;
17000
+ if (newCategoryId && newCategoryId !== categoryId) {
17001
+ const oldDocRef = doc34(
17002
+ this.getSubcategoriesRef(categoryId),
17003
+ subcategoryId
17004
+ );
17005
+ const docSnap = await getDoc36(oldDocRef);
17006
+ if (!docSnap.exists()) {
17007
+ throw new Error("Subcategory to update does not exist.");
17008
+ }
17009
+ const existingData = docSnap.data();
17010
+ const newData = {
17011
+ ...existingData,
17012
+ ...subcategory,
17013
+ categoryId: newCategoryId,
17014
+ // Ensure categoryId is updated
17015
+ createdAt: existingData.createdAt,
17016
+ // Preserve original creation date
17017
+ updatedAt: /* @__PURE__ */ new Date()
17018
+ };
17019
+ const newDocRef = doc34(
17020
+ this.getSubcategoriesRef(newCategoryId),
17021
+ subcategoryId
17022
+ );
17023
+ await setDoc28(newDocRef, newData);
17024
+ await deleteDoc20(oldDocRef);
17025
+ return { id: subcategoryId, ...newData };
17026
+ } else {
17027
+ const updateData = {
17028
+ ...subcategory,
17029
+ updatedAt: /* @__PURE__ */ new Date()
17030
+ };
17031
+ const docRef = doc34(this.getSubcategoriesRef(categoryId), subcategoryId);
17032
+ await updateDoc32(docRef, updateData);
17033
+ return this.getById(categoryId, subcategoryId);
17034
+ }
16559
17035
  }
16560
17036
  /**
16561
17037
  * Soft delete podkategorije (postavlja isActive na false)
@@ -16565,6 +17041,14 @@ var SubcategoryService = class extends BaseService {
16565
17041
  async delete(categoryId, subcategoryId) {
16566
17042
  await this.update(categoryId, subcategoryId, { isActive: false });
16567
17043
  }
17044
+ /**
17045
+ * Reactivates a subcategory by setting its isActive flag to true.
17046
+ * @param categoryId - The ID of the category to which the subcategory belongs.
17047
+ * @param subcategoryId - The ID of the subcategory to reactivate.
17048
+ */
17049
+ async reactivate(categoryId, subcategoryId) {
17050
+ await this.update(categoryId, subcategoryId, { isActive: true });
17051
+ }
16568
17052
  /**
16569
17053
  * Vraća podkategoriju po ID-u
16570
17054
  * @param categoryId - ID kategorije kojoj pripada podkategorija
@@ -16589,7 +17073,10 @@ import {
16589
17073
  doc as doc35,
16590
17074
  getDoc as getDoc37,
16591
17075
  getDocs as getDocs34,
17076
+ limit as limit19,
17077
+ orderBy as orderBy21,
16592
17078
  query as query34,
17079
+ startAfter as startAfter17,
16593
17080
  updateDoc as updateDoc33,
16594
17081
  where as where34,
16595
17082
  arrayUnion as arrayUnion9,
@@ -16601,137 +17088,185 @@ var DEFAULT_CERTIFICATION_REQUIREMENT = {
16601
17088
  };
16602
17089
  var TechnologyService = class extends BaseService {
16603
17090
  /**
16604
- * Vraća referencu na Firestore kolekciju tehnologija
17091
+ * Reference to the Firestore collection of technologies.
16605
17092
  */
16606
- getTechnologiesRef() {
17093
+ get technologiesRef() {
16607
17094
  return collection34(this.db, TECHNOLOGIES_COLLECTION);
16608
17095
  }
16609
17096
  /**
16610
- * Kreira novu tehnologiju
16611
- * @param technology - Podaci za novu tehnologiju
16612
- * @returns Kreirana tehnologija sa generisanim ID-em
17097
+ * Creates a new technology.
17098
+ * @param technology - Data for the new technology.
17099
+ * @returns The created technology with its generated ID.
16613
17100
  */
16614
17101
  async create(technology) {
16615
17102
  const now = /* @__PURE__ */ new Date();
16616
17103
  const newTechnology = {
16617
- ...technology,
16618
- createdAt: now,
16619
- updatedAt: now,
16620
- isActive: true,
16621
- requirements: technology.requirements || {
16622
- pre: [],
16623
- post: []
16624
- },
17104
+ name: technology.name,
17105
+ description: technology.description,
17106
+ family: technology.family,
17107
+ categoryId: technology.categoryId,
17108
+ subcategoryId: technology.subcategoryId,
17109
+ requirements: technology.requirements || { pre: [], post: [] },
16625
17110
  blockingConditions: technology.blockingConditions || [],
16626
17111
  contraindications: technology.contraindications || [],
16627
17112
  benefits: technology.benefits || [],
16628
- certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT
17113
+ certificationRequirement: technology.certificationRequirement || DEFAULT_CERTIFICATION_REQUIREMENT,
17114
+ documentationTemplates: technology.documentationTemplates || [],
17115
+ isActive: true,
17116
+ createdAt: now,
17117
+ updatedAt: now
16629
17118
  };
16630
- const docRef = await addDoc6(this.getTechnologiesRef(), newTechnology);
17119
+ if (technology.technicalDetails) {
17120
+ newTechnology.technicalDetails = technology.technicalDetails;
17121
+ }
17122
+ const docRef = await addDoc6(this.technologiesRef, newTechnology);
16631
17123
  return { id: docRef.id, ...newTechnology };
16632
17124
  }
16633
17125
  /**
16634
- * Vraća sve aktivne tehnologije
16635
- * @returns Lista aktivnih tehnologija
17126
+ * Returns counts of technologies for each subcategory.
17127
+ * @param active - Whether to count active or inactive technologies.
17128
+ * @returns A record mapping subcategory ID to technology count.
16636
17129
  */
16637
- async getAll() {
16638
- const q = query34(this.getTechnologiesRef(), where34("isActive", "==", true));
17130
+ async getTechnologyCounts(active = true) {
17131
+ const q = query34(this.technologiesRef, where34("isActive", "==", active));
16639
17132
  const snapshot = await getDocs34(q);
16640
- return snapshot.docs.map(
16641
- (doc37) => ({
16642
- id: doc37.id,
16643
- ...doc37.data()
16644
- })
16645
- );
17133
+ const counts = {};
17134
+ snapshot.docs.forEach((doc38) => {
17135
+ const tech = doc38.data();
17136
+ counts[tech.subcategoryId] = (counts[tech.subcategoryId] || 0) + 1;
17137
+ });
17138
+ return counts;
16646
17139
  }
16647
17140
  /**
16648
- * Vraća sve aktivne tehnologije za određenu familiju
16649
- * @param family - Familija procedura
16650
- * @returns Lista aktivnih tehnologija
17141
+ * Returns counts of technologies for each category.
17142
+ * @param active - Whether to count active or inactive technologies.
17143
+ * @returns A record mapping category ID to technology count.
16651
17144
  */
16652
- async getAllByFamily(family) {
16653
- const q = query34(
16654
- this.getTechnologiesRef(),
16655
- where34("isActive", "==", true),
16656
- where34("family", "==", family)
16657
- );
17145
+ async getTechnologyCountsByCategory(active = true) {
17146
+ const q = query34(this.technologiesRef, where34("isActive", "==", active));
16658
17147
  const snapshot = await getDocs34(q);
16659
- return snapshot.docs.map(
16660
- (doc37) => ({
16661
- id: doc37.id,
16662
- ...doc37.data()
17148
+ const counts = {};
17149
+ snapshot.docs.forEach((doc38) => {
17150
+ const tech = doc38.data();
17151
+ counts[tech.categoryId] = (counts[tech.categoryId] || 0) + 1;
17152
+ });
17153
+ return counts;
17154
+ }
17155
+ /**
17156
+ * Returns all technologies with pagination.
17157
+ * @param options - Pagination and filter options.
17158
+ * @returns A list of technologies and the last visible document.
17159
+ */
17160
+ async getAll(options = {}) {
17161
+ const { active = true, limit: queryLimit = 10, lastVisible } = options;
17162
+ const constraints = [
17163
+ where34("isActive", "==", active),
17164
+ orderBy21("name"),
17165
+ queryLimit ? limit19(queryLimit) : void 0,
17166
+ lastVisible ? startAfter17(lastVisible) : void 0
17167
+ ].filter((c) => !!c);
17168
+ const q = query34(this.technologiesRef, ...constraints);
17169
+ const snapshot = await getDocs34(q);
17170
+ const technologies = snapshot.docs.map(
17171
+ (doc38) => ({
17172
+ id: doc38.id,
17173
+ ...doc38.data()
16663
17174
  })
16664
17175
  );
17176
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
17177
+ return { technologies, lastVisible: newLastVisible };
16665
17178
  }
16666
17179
  /**
16667
- * Vraća sve aktivne tehnologije za određenu kategoriju
16668
- * @param categoryId - ID kategorije
16669
- * @returns Lista aktivnih tehnologija
17180
+ * Returns all technologies for a specific category with pagination.
17181
+ * @param categoryId - The ID of the category.
17182
+ * @param options - Pagination options.
17183
+ * @returns A list of technologies for the specified category.
16670
17184
  */
16671
- async getAllByCategoryId(categoryId) {
16672
- const q = query34(
16673
- this.getTechnologiesRef(),
16674
- where34("isActive", "==", true),
16675
- where34("categoryId", "==", categoryId)
16676
- );
17185
+ async getAllByCategoryId(categoryId, options = {}) {
17186
+ const { active = true, limit: queryLimit = 10, lastVisible } = options;
17187
+ const constraints = [
17188
+ where34("categoryId", "==", categoryId),
17189
+ where34("isActive", "==", active),
17190
+ orderBy21("name"),
17191
+ queryLimit ? limit19(queryLimit) : void 0,
17192
+ lastVisible ? startAfter17(lastVisible) : void 0
17193
+ ].filter((c) => !!c);
17194
+ const q = query34(this.technologiesRef, ...constraints);
16677
17195
  const snapshot = await getDocs34(q);
16678
- return snapshot.docs.map(
16679
- (doc37) => ({
16680
- id: doc37.id,
16681
- ...doc37.data()
17196
+ const technologies = snapshot.docs.map(
17197
+ (doc38) => ({
17198
+ id: doc38.id,
17199
+ ...doc38.data()
16682
17200
  })
16683
17201
  );
17202
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
17203
+ return { technologies, lastVisible: newLastVisible };
16684
17204
  }
16685
17205
  /**
16686
- * Vraća sve aktivne tehnologije za određenu podkategoriju
16687
- * @param subcategoryId - ID podkategorije
16688
- * @returns Lista aktivnih tehnologija
17206
+ * Returns all technologies for a specific subcategory with pagination.
17207
+ * @param subcategoryId - The ID of the subcategory.
17208
+ * @param options - Pagination options.
17209
+ * @returns A list of technologies for the specified subcategory.
16689
17210
  */
16690
- async getAllBySubcategoryId(subcategoryId) {
16691
- const q = query34(
16692
- this.getTechnologiesRef(),
16693
- where34("isActive", "==", true),
16694
- where34("subcategoryId", "==", subcategoryId)
16695
- );
17211
+ async getAllBySubcategoryId(subcategoryId, options = {}) {
17212
+ const { active = true, limit: queryLimit = 10, lastVisible } = options;
17213
+ const constraints = [
17214
+ where34("subcategoryId", "==", subcategoryId),
17215
+ where34("isActive", "==", active),
17216
+ orderBy21("name"),
17217
+ queryLimit ? limit19(queryLimit) : void 0,
17218
+ lastVisible ? startAfter17(lastVisible) : void 0
17219
+ ].filter((c) => !!c);
17220
+ const q = query34(this.technologiesRef, ...constraints);
16696
17221
  const snapshot = await getDocs34(q);
16697
- return snapshot.docs.map(
16698
- (doc37) => ({
16699
- id: doc37.id,
16700
- ...doc37.data()
17222
+ const technologies = snapshot.docs.map(
17223
+ (doc38) => ({
17224
+ id: doc38.id,
17225
+ ...doc38.data()
16701
17226
  })
16702
17227
  );
17228
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
17229
+ return { technologies, lastVisible: newLastVisible };
16703
17230
  }
16704
17231
  /**
16705
- * Ažurira postojeću tehnologiju
16706
- * @param technologyId - ID tehnologije
16707
- * @param technology - Novi podaci za tehnologiju
16708
- * @returns Ažurirana tehnologija
17232
+ * Updates an existing technology.
17233
+ * @param id - The ID of the technology to update.
17234
+ * @param technology - New data for the technology.
17235
+ * @returns The updated technology.
16709
17236
  */
16710
- async update(technologyId, technology) {
16711
- const updateData = {
16712
- ...technology,
16713
- updatedAt: /* @__PURE__ */ new Date()
16714
- };
16715
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17237
+ async update(id, technology) {
17238
+ const updateData = { ...technology };
17239
+ Object.keys(updateData).forEach((key) => {
17240
+ if (updateData[key] === void 0) {
17241
+ delete updateData[key];
17242
+ }
17243
+ });
17244
+ updateData.updatedAt = /* @__PURE__ */ new Date();
17245
+ const docRef = doc35(this.technologiesRef, id);
16716
17246
  await updateDoc33(docRef, updateData);
16717
- return this.getById(technologyId);
17247
+ return this.getById(id);
16718
17248
  }
16719
17249
  /**
16720
- * Soft delete tehnologije (postavlja isActive na false)
16721
- * @param technologyId - ID tehnologije koja se briše
17250
+ * Soft deletes a technology.
17251
+ * @param id - The ID of the technology to delete.
16722
17252
  */
16723
- async delete(technologyId) {
16724
- await this.update(technologyId, {
16725
- isActive: false
16726
- });
17253
+ async delete(id) {
17254
+ await this.update(id, { isActive: false });
16727
17255
  }
16728
17256
  /**
16729
- * Vraća tehnologiju po ID-u
16730
- * @param technologyId - ID tražene tehnologije
16731
- * @returns Tehnologija ili null ako ne postoji
17257
+ * Reactivates a technology.
17258
+ * @param id - The ID of the technology to reactivate.
16732
17259
  */
16733
- async getById(technologyId) {
16734
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17260
+ async reactivate(id) {
17261
+ await this.update(id, { isActive: true });
17262
+ }
17263
+ /**
17264
+ * Returns a technology by its ID.
17265
+ * @param id - The ID of the requested technology.
17266
+ * @returns The technology or null if it doesn't exist.
17267
+ */
17268
+ async getById(id) {
17269
+ const docRef = doc35(this.technologiesRef, id);
16735
17270
  const docSnap = await getDoc37(docRef);
16736
17271
  if (!docSnap.exists()) return null;
16737
17272
  return {
@@ -16746,7 +17281,7 @@ var TechnologyService = class extends BaseService {
16746
17281
  * @returns Ažurirana tehnologija sa novim zahtevom
16747
17282
  */
16748
17283
  async addRequirement(technologyId, requirement) {
16749
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17284
+ const docRef = doc35(this.technologiesRef, technologyId);
16750
17285
  const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
16751
17286
  await updateDoc33(docRef, {
16752
17287
  [requirementType]: arrayUnion9(requirement),
@@ -16761,7 +17296,7 @@ var TechnologyService = class extends BaseService {
16761
17296
  * @returns Ažurirana tehnologija bez uklonjenog zahteva
16762
17297
  */
16763
17298
  async removeRequirement(technologyId, requirement) {
16764
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17299
+ const docRef = doc35(this.technologiesRef, technologyId);
16765
17300
  const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
16766
17301
  await updateDoc33(docRef, {
16767
17302
  [requirementType]: arrayRemove8(requirement),
@@ -16801,7 +17336,7 @@ var TechnologyService = class extends BaseService {
16801
17336
  * @returns Ažurirana tehnologija
16802
17337
  */
16803
17338
  async addBlockingCondition(technologyId, condition) {
16804
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17339
+ const docRef = doc35(this.technologiesRef, technologyId);
16805
17340
  await updateDoc33(docRef, {
16806
17341
  blockingConditions: arrayUnion9(condition),
16807
17342
  updatedAt: /* @__PURE__ */ new Date()
@@ -16815,7 +17350,7 @@ var TechnologyService = class extends BaseService {
16815
17350
  * @returns Ažurirana tehnologija
16816
17351
  */
16817
17352
  async removeBlockingCondition(technologyId, condition) {
16818
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17353
+ const docRef = doc35(this.technologiesRef, technologyId);
16819
17354
  await updateDoc33(docRef, {
16820
17355
  blockingConditions: arrayRemove8(condition),
16821
17356
  updatedAt: /* @__PURE__ */ new Date()
@@ -16829,9 +17364,17 @@ var TechnologyService = class extends BaseService {
16829
17364
  * @returns Ažurirana tehnologija
16830
17365
  */
16831
17366
  async addContraindication(technologyId, contraindication) {
16832
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17367
+ const docRef = doc35(this.technologiesRef, technologyId);
17368
+ const technology = await this.getById(technologyId);
17369
+ if (!technology) {
17370
+ throw new Error(`Technology with id ${technologyId} not found`);
17371
+ }
17372
+ const existingContraindications = technology.contraindications || [];
17373
+ if (existingContraindications.some((c) => c.id === contraindication.id)) {
17374
+ return technology;
17375
+ }
16833
17376
  await updateDoc33(docRef, {
16834
- contraindications: arrayUnion9(contraindication),
17377
+ contraindications: [...existingContraindications, contraindication],
16835
17378
  updatedAt: /* @__PURE__ */ new Date()
16836
17379
  });
16837
17380
  return this.getById(technologyId);
@@ -16843,9 +17386,45 @@ var TechnologyService = class extends BaseService {
16843
17386
  * @returns Ažurirana tehnologija
16844
17387
  */
16845
17388
  async removeContraindication(technologyId, contraindication) {
16846
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17389
+ const docRef = doc35(this.technologiesRef, technologyId);
17390
+ const technology = await this.getById(technologyId);
17391
+ if (!technology) {
17392
+ throw new Error(`Technology with id ${technologyId} not found`);
17393
+ }
17394
+ const updatedContraindications = (technology.contraindications || []).filter((c) => c.id !== contraindication.id);
17395
+ await updateDoc33(docRef, {
17396
+ contraindications: updatedContraindications,
17397
+ updatedAt: /* @__PURE__ */ new Date()
17398
+ });
17399
+ return this.getById(technologyId);
17400
+ }
17401
+ /**
17402
+ * Updates an existing contraindication in a technology's list.
17403
+ * If the contraindication does not exist, it will not be added.
17404
+ * @param technologyId - ID of the technology
17405
+ * @param contraindication - The updated contraindication object
17406
+ * @returns The updated technology
17407
+ */
17408
+ async updateContraindication(technologyId, contraindication) {
17409
+ const docRef = doc35(this.technologiesRef, technologyId);
17410
+ const technology = await this.getById(technologyId);
17411
+ if (!technology) {
17412
+ throw new Error(`Technology with id ${technologyId} not found`);
17413
+ }
17414
+ const contraindications = technology.contraindications || [];
17415
+ const index = contraindications.findIndex(
17416
+ (c) => c.id === contraindication.id
17417
+ );
17418
+ if (index === -1) {
17419
+ console.warn(
17420
+ `Contraindication with id ${contraindication.id} not found for technology ${technologyId}. No update performed.`
17421
+ );
17422
+ return technology;
17423
+ }
17424
+ const updatedContraindications = [...contraindications];
17425
+ updatedContraindications[index] = contraindication;
16847
17426
  await updateDoc33(docRef, {
16848
- contraindications: arrayRemove8(contraindication),
17427
+ contraindications: updatedContraindications,
16849
17428
  updatedAt: /* @__PURE__ */ new Date()
16850
17429
  });
16851
17430
  return this.getById(technologyId);
@@ -16857,9 +17436,17 @@ var TechnologyService = class extends BaseService {
16857
17436
  * @returns Ažurirana tehnologija
16858
17437
  */
16859
17438
  async addBenefit(technologyId, benefit) {
16860
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17439
+ const docRef = doc35(this.technologiesRef, technologyId);
17440
+ const technology = await this.getById(technologyId);
17441
+ if (!technology) {
17442
+ throw new Error(`Technology with id ${technologyId} not found`);
17443
+ }
17444
+ const existingBenefits = technology.benefits || [];
17445
+ if (existingBenefits.some((b) => b.id === benefit.id)) {
17446
+ return technology;
17447
+ }
16861
17448
  await updateDoc33(docRef, {
16862
- benefits: arrayUnion9(benefit),
17449
+ benefits: [...existingBenefits, benefit],
16863
17450
  updatedAt: /* @__PURE__ */ new Date()
16864
17451
  });
16865
17452
  return this.getById(technologyId);
@@ -16871,9 +17458,45 @@ var TechnologyService = class extends BaseService {
16871
17458
  * @returns Ažurirana tehnologija
16872
17459
  */
16873
17460
  async removeBenefit(technologyId, benefit) {
16874
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17461
+ const docRef = doc35(this.technologiesRef, technologyId);
17462
+ const technology = await this.getById(technologyId);
17463
+ if (!technology) {
17464
+ throw new Error(`Technology with id ${technologyId} not found`);
17465
+ }
17466
+ const updatedBenefits = (technology.benefits || []).filter(
17467
+ (b) => b.id !== benefit.id
17468
+ );
17469
+ await updateDoc33(docRef, {
17470
+ benefits: updatedBenefits,
17471
+ updatedAt: /* @__PURE__ */ new Date()
17472
+ });
17473
+ return this.getById(technologyId);
17474
+ }
17475
+ /**
17476
+ * Updates an existing benefit in a technology's list.
17477
+ * If the benefit does not exist, it will not be added.
17478
+ * @param technologyId - ID of the technology
17479
+ * @param benefit - The updated benefit object
17480
+ * @returns The updated technology
17481
+ */
17482
+ async updateBenefit(technologyId, benefit) {
17483
+ const docRef = doc35(this.technologiesRef, technologyId);
17484
+ const technology = await this.getById(technologyId);
17485
+ if (!technology) {
17486
+ throw new Error(`Technology with id ${technologyId} not found`);
17487
+ }
17488
+ const benefits = technology.benefits || [];
17489
+ const index = benefits.findIndex((b) => b.id === benefit.id);
17490
+ if (index === -1) {
17491
+ console.warn(
17492
+ `Benefit with id ${benefit.id} not found for technology ${technologyId}. No update performed.`
17493
+ );
17494
+ return technology;
17495
+ }
17496
+ const updatedBenefits = [...benefits];
17497
+ updatedBenefits[index] = benefit;
16875
17498
  await updateDoc33(docRef, {
16876
- benefits: arrayRemove8(benefit),
17499
+ benefits: updatedBenefits,
16877
17500
  updatedAt: /* @__PURE__ */ new Date()
16878
17501
  });
16879
17502
  return this.getById(technologyId);
@@ -16912,7 +17535,7 @@ var TechnologyService = class extends BaseService {
16912
17535
  * @returns Ažurirana tehnologija
16913
17536
  */
16914
17537
  async updateCertificationRequirement(technologyId, certificationRequirement) {
16915
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17538
+ const docRef = doc35(this.technologiesRef, technologyId);
16916
17539
  await updateDoc33(docRef, {
16917
17540
  certificationRequirement,
16918
17541
  updatedAt: /* @__PURE__ */ new Date()
@@ -16990,7 +17613,7 @@ var TechnologyService = class extends BaseService {
16990
17613
  */
16991
17614
  async getAllowedTechnologies(practitioner) {
16992
17615
  const allTechnologies = await this.getAll();
16993
- const allowedTechnologies = allTechnologies.filter(
17616
+ const allowedTechnologies = allTechnologies.technologies.filter(
16994
17617
  (technology) => this.validateCertification(
16995
17618
  technology.certificationRequirement,
16996
17619
  practitioner.certification
@@ -17010,18 +17633,61 @@ var TechnologyService = class extends BaseService {
17010
17633
  subcategories
17011
17634
  };
17012
17635
  }
17636
+ /**
17637
+ * Gets all active technologies for a subcategory for filter dropdowns.
17638
+ * @param categoryId - The ID of the parent category.
17639
+ * @param subcategoryId - The ID of the subcategory.
17640
+ */
17641
+ async getAllForFilterBySubcategoryId(categoryId, subcategoryId) {
17642
+ const q = query34(
17643
+ collection34(this.db, TECHNOLOGIES_COLLECTION),
17644
+ where34("isActive", "==", true),
17645
+ where34("categoryId", "==", categoryId),
17646
+ where34("subcategoryId", "==", subcategoryId),
17647
+ orderBy21("name")
17648
+ );
17649
+ const snapshot = await getDocs34(q);
17650
+ return snapshot.docs.map(
17651
+ (doc38) => ({
17652
+ id: doc38.id,
17653
+ ...doc38.data()
17654
+ })
17655
+ );
17656
+ }
17657
+ /**
17658
+ * Gets all active technologies for filter dropdowns.
17659
+ */
17660
+ async getAllForFilter() {
17661
+ const q = query34(
17662
+ collection34(this.db, TECHNOLOGIES_COLLECTION),
17663
+ where34("isActive", "==", true),
17664
+ orderBy21("name")
17665
+ );
17666
+ const snapshot = await getDocs34(q);
17667
+ return snapshot.docs.map(
17668
+ (doc38) => ({
17669
+ id: doc38.id,
17670
+ ...doc38.data()
17671
+ })
17672
+ );
17673
+ }
17013
17674
  };
17014
17675
 
17015
17676
  // src/backoffice/services/product.service.ts
17016
17677
  import {
17017
17678
  addDoc as addDoc7,
17018
17679
  collection as collection35,
17680
+ collectionGroup as collectionGroup3,
17019
17681
  doc as doc36,
17020
17682
  getDoc as getDoc38,
17021
17683
  getDocs as getDocs35,
17022
17684
  query as query35,
17023
17685
  updateDoc as updateDoc34,
17024
- where as where35
17686
+ where as where35,
17687
+ limit as limit20,
17688
+ orderBy as orderBy22,
17689
+ startAfter as startAfter18,
17690
+ getCountFromServer as getCountFromServer6
17025
17691
  } from "firebase/firestore";
17026
17692
 
17027
17693
  // src/backoffice/types/product.types.ts
@@ -17062,20 +17728,102 @@ var ProductService = class extends BaseService {
17062
17728
  return { id: productRef.id, ...newProduct };
17063
17729
  }
17064
17730
  /**
17065
- * Gets all products for a technology
17731
+ * Gets a paginated list of all products, with optional filters.
17732
+ * This uses a collectionGroup query to search across all technologies.
17066
17733
  */
17067
- async getAllByTechnology(technologyId) {
17734
+ async getAll(options) {
17735
+ const {
17736
+ rowsPerPage,
17737
+ lastVisible,
17738
+ categoryId,
17739
+ subcategoryId,
17740
+ technologyId
17741
+ } = options;
17742
+ const constraints = [
17743
+ where35("isActive", "==", true),
17744
+ orderBy22("name")
17745
+ ];
17746
+ if (categoryId) {
17747
+ constraints.push(where35("categoryId", "==", categoryId));
17748
+ }
17749
+ if (subcategoryId) {
17750
+ constraints.push(where35("subcategoryId", "==", subcategoryId));
17751
+ }
17752
+ if (technologyId) {
17753
+ constraints.push(where35("technologyId", "==", technologyId));
17754
+ }
17755
+ if (lastVisible) {
17756
+ constraints.push(startAfter18(lastVisible));
17757
+ }
17758
+ constraints.push(limit20(rowsPerPage));
17068
17759
  const q = query35(
17069
- this.getProductsRef(technologyId),
17070
- where35("isActive", "==", true)
17760
+ collectionGroup3(this.db, PRODUCTS_COLLECTION),
17761
+ ...constraints
17071
17762
  );
17072
17763
  const snapshot = await getDocs35(q);
17073
- return snapshot.docs.map(
17074
- (doc37) => ({
17075
- id: doc37.id,
17076
- ...doc37.data()
17764
+ const products = snapshot.docs.map(
17765
+ (doc38) => ({
17766
+ id: doc38.id,
17767
+ ...doc38.data()
17077
17768
  })
17078
17769
  );
17770
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
17771
+ return { products, lastVisible: newLastVisible };
17772
+ }
17773
+ /**
17774
+ * Gets the total count of active products, with optional filters.
17775
+ */
17776
+ async getProductsCount(options) {
17777
+ const { categoryId, subcategoryId, technologyId } = options;
17778
+ const constraints = [where35("isActive", "==", true)];
17779
+ if (categoryId) {
17780
+ constraints.push(where35("categoryId", "==", categoryId));
17781
+ }
17782
+ if (subcategoryId) {
17783
+ constraints.push(where35("subcategoryId", "==", subcategoryId));
17784
+ }
17785
+ if (technologyId) {
17786
+ constraints.push(where35("technologyId", "==", technologyId));
17787
+ }
17788
+ const q = query35(
17789
+ collectionGroup3(this.db, PRODUCTS_COLLECTION),
17790
+ ...constraints
17791
+ );
17792
+ const snapshot = await getCountFromServer6(q);
17793
+ return snapshot.data().count;
17794
+ }
17795
+ /**
17796
+ * Gets counts of active products grouped by category, subcategory, and technology.
17797
+ * This uses a single collectionGroup query for efficiency.
17798
+ */
17799
+ async getProductCounts() {
17800
+ const q = query35(
17801
+ collectionGroup3(this.db, PRODUCTS_COLLECTION),
17802
+ where35("isActive", "==", true)
17803
+ );
17804
+ const snapshot = await getDocs35(q);
17805
+ const counts = {
17806
+ byCategory: {},
17807
+ bySubcategory: {},
17808
+ byTechnology: {}
17809
+ };
17810
+ if (snapshot.empty) {
17811
+ return counts;
17812
+ }
17813
+ snapshot.docs.forEach((doc38) => {
17814
+ const product = doc38.data();
17815
+ const { categoryId, subcategoryId, technologyId } = product;
17816
+ if (categoryId) {
17817
+ counts.byCategory[categoryId] = (counts.byCategory[categoryId] || 0) + 1;
17818
+ }
17819
+ if (subcategoryId) {
17820
+ counts.bySubcategory[subcategoryId] = (counts.bySubcategory[subcategoryId] || 0) + 1;
17821
+ }
17822
+ if (technologyId) {
17823
+ counts.byTechnology[technologyId] = (counts.byTechnology[technologyId] || 0) + 1;
17824
+ }
17825
+ });
17826
+ return counts;
17079
17827
  }
17080
17828
  /**
17081
17829
  * Gets all products for a brand by filtering through all technologies
@@ -17093,9 +17841,9 @@ var ProductService = class extends BaseService {
17093
17841
  const snapshot = await getDocs35(q);
17094
17842
  products.push(
17095
17843
  ...snapshot.docs.map(
17096
- (doc37) => ({
17097
- id: doc37.id,
17098
- ...doc37.data()
17844
+ (doc38) => ({
17845
+ id: doc38.id,
17846
+ ...doc38.data()
17099
17847
  })
17100
17848
  )
17101
17849
  );
@@ -17136,6 +17884,262 @@ var ProductService = class extends BaseService {
17136
17884
  }
17137
17885
  };
17138
17886
 
17887
+ // src/backoffice/services/constants.service.ts
17888
+ import {
17889
+ arrayRemove as arrayRemove9,
17890
+ arrayUnion as arrayUnion10,
17891
+ doc as doc37,
17892
+ getDoc as getDoc39,
17893
+ setDoc as setDoc29,
17894
+ updateDoc as updateDoc35
17895
+ } from "firebase/firestore";
17896
+ var ADMIN_CONSTANTS_COLLECTION = "admin-constants";
17897
+ var TREATMENT_BENEFITS_DOC = "treatment-benefits";
17898
+ var CONTRAINDICATIONS_DOC = "contraindications";
17899
+ var ConstantsService = class extends BaseService {
17900
+ /**
17901
+ * @description Gets the reference to the document holding treatment benefits.
17902
+ * @private
17903
+ * @type {DocumentReference}
17904
+ */
17905
+ get treatmentBenefitsDocRef() {
17906
+ return doc37(this.db, ADMIN_CONSTANTS_COLLECTION, TREATMENT_BENEFITS_DOC);
17907
+ }
17908
+ /**
17909
+ * @description Gets the reference to the document holding contraindications.
17910
+ * @private
17911
+ * @type {DocumentReference}
17912
+ */
17913
+ get contraindicationsDocRef() {
17914
+ return doc37(this.db, ADMIN_CONSTANTS_COLLECTION, CONTRAINDICATIONS_DOC);
17915
+ }
17916
+ // =================================================================
17917
+ // Treatment Benefits
17918
+ // =================================================================
17919
+ /**
17920
+ * @description Retrieves all treatment benefits without pagination.
17921
+ * @returns {Promise<TreatmentBenefitDynamic[]>} An array of all treatment benefits.
17922
+ */
17923
+ async getAllBenefitsForFilter() {
17924
+ const docSnap = await getDoc39(this.treatmentBenefitsDocRef);
17925
+ if (!docSnap.exists()) {
17926
+ return [];
17927
+ }
17928
+ return docSnap.data().benefits;
17929
+ }
17930
+ /**
17931
+ * @description Retrieves a paginated list of treatment benefits.
17932
+ * @param {{ page: number; limit: number }} options - Pagination options.
17933
+ * @returns {Promise<{ benefits: TreatmentBenefitDynamic[]; total: number }>} A paginated list of benefits and the total count.
17934
+ */
17935
+ async getAllBenefits(options) {
17936
+ const allBenefits = await this.getAllBenefitsForFilter();
17937
+ const { page, limit: limit21 } = options;
17938
+ const startIndex = page * limit21;
17939
+ const endIndex = startIndex + limit21;
17940
+ const paginatedBenefits = allBenefits.slice(startIndex, endIndex);
17941
+ return { benefits: paginatedBenefits, total: allBenefits.length };
17942
+ }
17943
+ /**
17944
+ * @description Adds a new treatment benefit.
17945
+ * @param {Omit<TreatmentBenefitDynamic, "id">} benefit - The treatment benefit to add, without an ID.
17946
+ * @returns {Promise<TreatmentBenefitDynamic>} The newly created treatment benefit with its generated ID.
17947
+ */
17948
+ async addTreatmentBenefit(benefit) {
17949
+ const newBenefit = {
17950
+ id: this.generateId(),
17951
+ ...benefit
17952
+ };
17953
+ const docSnap = await getDoc39(this.treatmentBenefitsDocRef);
17954
+ if (!docSnap.exists()) {
17955
+ await setDoc29(this.treatmentBenefitsDocRef, { benefits: [newBenefit] });
17956
+ } else {
17957
+ await updateDoc35(this.treatmentBenefitsDocRef, {
17958
+ benefits: arrayUnion10(newBenefit)
17959
+ });
17960
+ }
17961
+ return newBenefit;
17962
+ }
17963
+ /**
17964
+ * @description Retrieves a single treatment benefit by its ID.
17965
+ * @param {string} benefitId - The ID of the treatment benefit to retrieve.
17966
+ * @returns {Promise<TreatmentBenefitDynamic | undefined>} The found treatment benefit or undefined.
17967
+ */
17968
+ async getBenefitById(benefitId) {
17969
+ const benefits = await this.getAllBenefitsForFilter();
17970
+ return benefits.find((b) => b.id === benefitId);
17971
+ }
17972
+ /**
17973
+ * @description Searches for treatment benefits by name (case-insensitive).
17974
+ * @param {string} searchTerm - The term to search for in the benefit names.
17975
+ * @returns {Promise<TreatmentBenefitDynamic[]>} An array of matching treatment benefits.
17976
+ */
17977
+ async searchBenefitsByName(searchTerm) {
17978
+ const benefits = await this.getAllBenefitsForFilter();
17979
+ const normalizedSearchTerm = searchTerm.toLowerCase();
17980
+ return benefits.filter(
17981
+ (b) => b.name.toLowerCase().includes(normalizedSearchTerm)
17982
+ );
17983
+ }
17984
+ /**
17985
+ * @description Updates an existing treatment benefit.
17986
+ * @param {TreatmentBenefitDynamic} benefit - The treatment benefit with updated data. Its ID must match an existing benefit.
17987
+ * @returns {Promise<TreatmentBenefitDynamic>} The updated treatment benefit.
17988
+ * @throws {Error} If the treatment benefit is not found.
17989
+ */
17990
+ async updateTreatmentBenefit(benefit) {
17991
+ const benefits = await this.getAllBenefitsForFilter();
17992
+ const benefitIndex = benefits.findIndex((b) => b.id === benefit.id);
17993
+ if (benefitIndex === -1) {
17994
+ throw new Error("Treatment benefit not found.");
17995
+ }
17996
+ benefits[benefitIndex] = benefit;
17997
+ await updateDoc35(this.treatmentBenefitsDocRef, { benefits });
17998
+ return benefit;
17999
+ }
18000
+ /**
18001
+ * @description Deletes a treatment benefit by its ID.
18002
+ * @param {string} benefitId - The ID of the treatment benefit to delete.
18003
+ * @returns {Promise<void>}
18004
+ */
18005
+ async deleteTreatmentBenefit(benefitId) {
18006
+ const benefits = await this.getAllBenefitsForFilter();
18007
+ const benefitToRemove = benefits.find((b) => b.id === benefitId);
18008
+ if (!benefitToRemove) {
18009
+ return;
18010
+ }
18011
+ await updateDoc35(this.treatmentBenefitsDocRef, {
18012
+ benefits: arrayRemove9(benefitToRemove)
18013
+ });
18014
+ }
18015
+ // =================================================================
18016
+ // Contraindications
18017
+ // =================================================================
18018
+ /**
18019
+ * @description Retrieves all contraindications without pagination.
18020
+ * @returns {Promise<ContraindicationDynamic[]>} An array of all contraindications.
18021
+ */
18022
+ async getAllContraindicationsForFilter() {
18023
+ const docSnap = await getDoc39(this.contraindicationsDocRef);
18024
+ if (!docSnap.exists()) {
18025
+ return [];
18026
+ }
18027
+ return docSnap.data().contraindications;
18028
+ }
18029
+ /**
18030
+ * @description Retrieves a paginated list of contraindications.
18031
+ * @param {{ page: number; limit: number }} options - Pagination options.
18032
+ * @returns {Promise<{ contraindications: ContraindicationDynamic[]; total: number }>} A paginated list and the total count.
18033
+ */
18034
+ async getAllContraindications(options) {
18035
+ const allContraindications = await this.getAllContraindicationsForFilter();
18036
+ const { page, limit: limit21 } = options;
18037
+ const startIndex = page * limit21;
18038
+ const endIndex = startIndex + limit21;
18039
+ const paginatedContraindications = allContraindications.slice(
18040
+ startIndex,
18041
+ endIndex
18042
+ );
18043
+ return {
18044
+ contraindications: paginatedContraindications,
18045
+ total: allContraindications.length
18046
+ };
18047
+ }
18048
+ /**
18049
+ * @description Adds a new contraindication.
18050
+ * @param {Omit<ContraindicationDynamic, "id">} contraindication - The contraindication to add, without an ID.
18051
+ * @returns {Promise<ContraindicationDynamic>} The newly created contraindication with its generated ID.
18052
+ */
18053
+ async addContraindication(contraindication) {
18054
+ const newContraindication = {
18055
+ id: this.generateId(),
18056
+ ...contraindication
18057
+ };
18058
+ const docSnap = await getDoc39(this.contraindicationsDocRef);
18059
+ if (!docSnap.exists()) {
18060
+ await setDoc29(this.contraindicationsDocRef, {
18061
+ contraindications: [newContraindication]
18062
+ });
18063
+ } else {
18064
+ await updateDoc35(this.contraindicationsDocRef, {
18065
+ contraindications: arrayUnion10(newContraindication)
18066
+ });
18067
+ }
18068
+ return newContraindication;
18069
+ }
18070
+ /**
18071
+ * @description Retrieves a single contraindication by its ID.
18072
+ * @param {string} contraindicationId - The ID of the contraindication to retrieve.
18073
+ * @returns {Promise<ContraindicationDynamic | undefined>} The found contraindication or undefined.
18074
+ */
18075
+ async getContraindicationById(contraindicationId) {
18076
+ const contraindications = await this.getAllContraindicationsForFilter();
18077
+ return contraindications.find((c) => c.id === contraindicationId);
18078
+ }
18079
+ /**
18080
+ * @description Searches for contraindications by name (case-insensitive).
18081
+ * @param {string} searchTerm - The term to search for in the contraindication names.
18082
+ * @returns {Promise<ContraindicationDynamic[]>} An array of matching contraindications.
18083
+ */
18084
+ async searchContraindicationsByName(searchTerm) {
18085
+ const contraindications = await this.getAllContraindicationsForFilter();
18086
+ const normalizedSearchTerm = searchTerm.toLowerCase();
18087
+ return contraindications.filter(
18088
+ (c) => c.name.toLowerCase().includes(normalizedSearchTerm)
18089
+ );
18090
+ }
18091
+ /**
18092
+ * @description Updates an existing contraindication.
18093
+ * @param {ContraindicationDynamic} contraindication - The contraindication with updated data. Its ID must match an existing one.
18094
+ * @returns {Promise<ContraindicationDynamic>} The updated contraindication.
18095
+ * @throws {Error} If the contraindication is not found.
18096
+ */
18097
+ async updateContraindication(contraindication) {
18098
+ const contraindications = await this.getAllContraindicationsForFilter();
18099
+ const index = contraindications.findIndex(
18100
+ (c) => c.id === contraindication.id
18101
+ );
18102
+ if (index === -1) {
18103
+ throw new Error("Contraindication not found.");
18104
+ }
18105
+ contraindications[index] = contraindication;
18106
+ await updateDoc35(this.contraindicationsDocRef, { contraindications });
18107
+ return contraindication;
18108
+ }
18109
+ /**
18110
+ * @description Deletes a contraindication by its ID.
18111
+ * @param {string} contraindicationId - The ID of the contraindication to delete.
18112
+ * @returns {Promise<void>}
18113
+ */
18114
+ async deleteContraindication(contraindicationId) {
18115
+ const contraindications = await this.getAllContraindicationsForFilter();
18116
+ const toRemove = contraindications.find((c) => c.id === contraindicationId);
18117
+ if (!toRemove) {
18118
+ return;
18119
+ }
18120
+ await updateDoc35(this.contraindicationsDocRef, {
18121
+ contraindications: arrayRemove9(toRemove)
18122
+ });
18123
+ }
18124
+ };
18125
+
18126
+ // src/backoffice/types/static/contraindication.types.ts
18127
+ var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
18128
+ Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
18129
+ Contraindication2["RECENT_TANNING"] = "recent_tanning";
18130
+ Contraindication2["RECENT_BOTOX"] = "recent_botox";
18131
+ Contraindication2["RECENT_FILLERS"] = "recent_fillers";
18132
+ Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
18133
+ Contraindication2["MEDICATIONS"] = "medications";
18134
+ Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
18135
+ Contraindication2["RECENT_LASER"] = "recent_laser";
18136
+ Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
18137
+ Contraindication2["OPEN_WOUNDS"] = "open_wounds";
18138
+ Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
18139
+ Contraindication2["COLD_SORES"] = "cold_sores";
18140
+ return Contraindication2;
18141
+ })(Contraindication || {});
18142
+
17139
18143
  // src/backoffice/types/static/treatment-benefit.types.ts
17140
18144
  var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
17141
18145
  TreatmentBenefit2["WRINKLE_REDUCTION"] = "wrinkle_reduction";
@@ -17194,6 +18198,7 @@ export {
17194
18198
  ClinicPhotoTag,
17195
18199
  ClinicService,
17196
18200
  ClinicTag,
18201
+ ConstantsService,
17197
18202
  Contraindication,
17198
18203
  CosmeticAllergySubtype,
17199
18204
  Currency,