@blackcode_sa/metaestetics-api 1.11.2 → 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 (49) hide show
  1. package/dist/admin/index.d.mts +331 -318
  2. package/dist/admin/index.d.ts +331 -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 +4429 -4034
  8. package/dist/index.d.ts +4429 -4034
  9. package/dist/index.js +1644 -666
  10. package/dist/index.mjs +1408 -402
  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 +4 -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/appointment.schema.ts +1 -0
  42. package/src/validations/clinic.schema.ts +1 -6
  43. package/src/validations/patient/medical-info.schema.ts +7 -2
  44. package/src/backoffice/services/__tests__/brand.service.test.ts +0 -196
  45. package/src/backoffice/services/__tests__/category.service.test.ts +0 -201
  46. package/src/backoffice/services/__tests__/product.service.test.ts +0 -358
  47. package/src/backoffice/services/__tests__/requirement.service.test.ts +0 -226
  48. package/src/backoffice/services/__tests__/subcategory.service.test.ts +0 -181
  49. 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";
@@ -438,7 +440,8 @@ var appointmentMetadataSchema = z3.object({
438
440
  selectedZones: z3.array(z3.string()).nullable(),
439
441
  zonePhotos: z3.record(z3.string(), beforeAfterPerZoneSchema).nullable(),
440
442
  zoneBilling: z3.record(z3.string(), billingPerZoneSchema).nullable(),
441
- finalbilling: finalBillingSchema.nullable()
443
+ finalbilling: finalBillingSchema.nullable(),
444
+ finalizationNotes: z3.string().nullable()
442
445
  });
443
446
  var createAppointmentSchema = z3.object({
444
447
  clinicBranchId: z3.string().min(MIN_STRING_LENGTH, "Clinic branch ID is required"),
@@ -581,7 +584,6 @@ import {
581
584
  getDocs,
582
585
  query,
583
586
  where,
584
- setDoc,
585
587
  updateDoc,
586
588
  serverTimestamp,
587
589
  Timestamp,
@@ -818,44 +820,48 @@ async function updateAppointmentUtil(db, appointmentId, data) {
818
820
  const validPreReqIds = currentAppointment.preProcedureRequirements.map(
819
821
  (req) => req.id
820
822
  );
821
- const invalidPreReqIds = data.completedPreRequirements.filter(
822
- (id) => !validPreReqIds.includes(id)
823
- );
824
- if (invalidPreReqIds.length > 0) {
825
- throw new Error(
826
- `Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
823
+ if (Array.isArray(data.completedPreRequirements)) {
824
+ const invalidPreReqIds = data.completedPreRequirements.filter(
825
+ (id) => !validPreReqIds.includes(id)
827
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
+ ];
828
838
  }
829
- completedPreRequirements = [
830
- .../* @__PURE__ */ new Set([
831
- ...completedPreRequirements,
832
- ...data.completedPreRequirements
833
- ])
834
- ];
835
839
  }
836
840
  if (data.completedPostRequirements) {
837
841
  const validPostReqIds = currentAppointment.postProcedureRequirements.map(
838
842
  (req) => req.id
839
843
  );
840
- const invalidPostReqIds = data.completedPostRequirements.filter(
841
- (id) => !validPostReqIds.includes(id)
842
- );
843
- if (invalidPostReqIds.length > 0) {
844
- throw new Error(
845
- `Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
844
+ if (Array.isArray(data.completedPostRequirements)) {
845
+ const invalidPostReqIds = data.completedPostRequirements.filter(
846
+ (id) => !validPostReqIds.includes(id)
846
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
+ ];
847
859
  }
848
- completedPostRequirements = [
849
- .../* @__PURE__ */ new Set([
850
- ...completedPostRequirements,
851
- ...data.completedPostRequirements
852
- ])
853
- ];
854
860
  }
855
861
  const updateData = {
856
862
  ...data,
857
- completedPreRequirements,
858
- completedPostRequirements,
863
+ completedPreRequirements: Array.isArray(data.completedPreRequirements) ? completedPreRequirements : data.completedPreRequirements,
864
+ completedPostRequirements: Array.isArray(data.completedPostRequirements) ? completedPostRequirements : data.completedPostRequirements,
859
865
  updatedAt: serverTimestamp()
860
866
  };
861
867
  Object.keys(updateData).forEach((key) => {
@@ -905,7 +911,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
905
911
  case "canceled_clinic" /* CANCELED_CLINIC */:
906
912
  calendarStatus = "canceled";
907
913
  break;
908
- case AppointmentStatus.RESCHEDULED:
914
+ case "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */:
909
915
  calendarStatus = "rescheduled";
910
916
  break;
911
917
  case "completed" /* COMPLETED */:
@@ -979,7 +985,7 @@ async function searchAppointmentsUtil(db, params) {
979
985
  const q = query(collection(db, APPOINTMENTS_COLLECTION), ...constraints);
980
986
  const querySnapshot = await getDocs(q);
981
987
  const appointments = querySnapshot.docs.map(
982
- (doc37) => doc37.data()
988
+ (doc38) => doc38.data()
983
989
  );
984
990
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
985
991
  return { appointments, lastDoc };
@@ -1786,7 +1792,7 @@ var AppointmentService = class extends BaseService {
1786
1792
  );
1787
1793
  const querySnapshot = await getDocs2(q);
1788
1794
  const appointments = querySnapshot.docs.map(
1789
- (doc37) => doc37.data()
1795
+ (doc38) => doc38.data()
1790
1796
  );
1791
1797
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1792
1798
  console.log(
@@ -1859,7 +1865,7 @@ var AppointmentService = class extends BaseService {
1859
1865
  );
1860
1866
  const querySnapshot = await getDocs2(q);
1861
1867
  const appointments = querySnapshot.docs.map(
1862
- (doc37) => doc37.data()
1868
+ (doc38) => doc38.data()
1863
1869
  );
1864
1870
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
1865
1871
  console.log(
@@ -2411,8 +2417,8 @@ var MediaAccessLevel = /* @__PURE__ */ ((MediaAccessLevel2) => {
2411
2417
  })(MediaAccessLevel || {});
2412
2418
  var MEDIA_METADATA_COLLECTION = "media_metadata";
2413
2419
  var MediaService = class extends BaseService {
2414
- constructor(db, auth, app) {
2415
- super(db, auth, app);
2420
+ constructor(...args) {
2421
+ super(...args);
2416
2422
  }
2417
2423
  /**
2418
2424
  * Upload a media file, store its metadata, and return the metadata including the URL.
@@ -2672,7 +2678,7 @@ var MediaService = class extends BaseService {
2672
2678
  try {
2673
2679
  const querySnapshot = await getDocs3(finalQuery);
2674
2680
  const mediaList = querySnapshot.docs.map(
2675
- (doc37) => doc37.data()
2681
+ (doc38) => doc38.data()
2676
2682
  );
2677
2683
  console.log(`[MediaService] Found ${mediaList.length} media items.`);
2678
2684
  return mediaList;
@@ -2735,8 +2741,8 @@ var getPatientsByClinicUtil = async (db, clinicId, options) => {
2735
2741
  }
2736
2742
  const patientsSnapshot = await getDocs4(q);
2737
2743
  const patients = [];
2738
- patientsSnapshot.forEach((doc37) => {
2739
- patients.push(doc37.data());
2744
+ patientsSnapshot.forEach((doc38) => {
2745
+ patients.push(doc38.data());
2740
2746
  });
2741
2747
  console.log(
2742
2748
  `[getPatientsByClinicUtil] Found ${patients.length} patients for clinic ID: ${clinicId}`
@@ -2798,23 +2804,6 @@ var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
2798
2804
  return BlockingCondition2;
2799
2805
  })(BlockingCondition || {});
2800
2806
 
2801
- // src/backoffice/types/static/contraindication.types.ts
2802
- var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
2803
- Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
2804
- Contraindication2["RECENT_TANNING"] = "recent_tanning";
2805
- Contraindication2["RECENT_BOTOX"] = "recent_botox";
2806
- Contraindication2["RECENT_FILLERS"] = "recent_fillers";
2807
- Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
2808
- Contraindication2["MEDICATIONS"] = "medications";
2809
- Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
2810
- Contraindication2["RECENT_LASER"] = "recent_laser";
2811
- Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
2812
- Contraindication2["OPEN_WOUNDS"] = "open_wounds";
2813
- Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
2814
- Contraindication2["COLD_SORES"] = "cold_sores";
2815
- return Contraindication2;
2816
- })(Contraindication || {});
2817
-
2818
2807
  // src/validations/common.schema.ts
2819
2808
  import { z as z5 } from "zod";
2820
2809
  import { Timestamp as Timestamp4 } from "firebase/firestore";
@@ -2869,8 +2858,13 @@ var blockingConditionSchema = z6.object({
2869
2858
  notes: z6.string().optional().nullable(),
2870
2859
  isActive: z6.boolean()
2871
2860
  });
2861
+ var contraindicationDynamicSchema = z6.object({
2862
+ id: z6.string(),
2863
+ name: z6.string(),
2864
+ description: z6.string().optional()
2865
+ });
2872
2866
  var contraindicationSchema = z6.object({
2873
- condition: z6.nativeEnum(Contraindication),
2867
+ condition: contraindicationDynamicSchema,
2874
2868
  lastOccurrence: timestampSchema,
2875
2869
  frequency: z6.enum(["rare", "occasional", "frequent"]),
2876
2870
  notes: z6.string().optional().nullable(),
@@ -3110,8 +3104,8 @@ var getPatientsByPractitionerUtil = async (db, practitionerId, options) => {
3110
3104
  }
3111
3105
  const patientsSnapshot = await getDocs5(q);
3112
3106
  const patients = [];
3113
- patientsSnapshot.forEach((doc37) => {
3114
- patients.push(doc37.data());
3107
+ patientsSnapshot.forEach((doc38) => {
3108
+ patients.push(doc38.data());
3115
3109
  });
3116
3110
  console.log(
3117
3111
  `[getPatientsByPractitionerUtil] Found ${patients.length} patients for practitioner ID: ${practitionerId}`
@@ -3890,7 +3884,7 @@ async function getClinicAdminsByGroup(db, clinicGroupId) {
3890
3884
  where6("clinicGroupId", "==", clinicGroupId)
3891
3885
  );
3892
3886
  const querySnapshot = await getDocs6(q);
3893
- return querySnapshot.docs.map((doc37) => doc37.data());
3887
+ return querySnapshot.docs.map((doc38) => doc38.data());
3894
3888
  }
3895
3889
  async function updateClinicAdmin(db, adminId, data) {
3896
3890
  const admin = await getClinicAdmin(db, adminId);
@@ -4571,9 +4565,9 @@ var updateAllergyUtil = async (db, patientId, data, requesterId, requesterRoles)
4571
4565
  };
4572
4566
  var removeAllergyUtil = async (db, patientId, allergyIndex, requesterId, requesterRoles) => {
4573
4567
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4574
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4575
- if (!doc37.exists()) throw new Error("Medical info not found");
4576
- 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();
4577
4571
  if (allergyIndex >= medicalInfo.allergies.length) {
4578
4572
  throw new Error("Invalid allergy index");
4579
4573
  }
@@ -4600,9 +4594,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, requesterId, reque
4600
4594
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4601
4595
  const validatedData = updateBlockingConditionSchema.parse(data);
4602
4596
  const { conditionIndex, ...updateData } = validatedData;
4603
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4604
- if (!doc37.exists()) throw new Error("Medical info not found");
4605
- 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();
4606
4600
  if (conditionIndex >= medicalInfo.blockingConditions.length) {
4607
4601
  throw new Error("Invalid blocking condition index");
4608
4602
  }
@@ -4619,9 +4613,9 @@ var updateBlockingConditionUtil = async (db, patientId, data, requesterId, reque
4619
4613
  };
4620
4614
  var removeBlockingConditionUtil = async (db, patientId, conditionIndex, requesterId, requesterRoles) => {
4621
4615
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4622
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4623
- if (!doc37.exists()) throw new Error("Medical info not found");
4624
- 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();
4625
4619
  if (conditionIndex >= medicalInfo.blockingConditions.length) {
4626
4620
  throw new Error("Invalid blocking condition index");
4627
4621
  }
@@ -4648,9 +4642,9 @@ var updateContraindicationUtil = async (db, patientId, data, requesterId, reques
4648
4642
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4649
4643
  const validatedData = updateContraindicationSchema.parse(data);
4650
4644
  const { contraindicationIndex, ...updateData } = validatedData;
4651
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4652
- if (!doc37.exists()) throw new Error("Medical info not found");
4653
- 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();
4654
4648
  if (contraindicationIndex >= medicalInfo.contraindications.length) {
4655
4649
  throw new Error("Invalid contraindication index");
4656
4650
  }
@@ -4667,9 +4661,9 @@ var updateContraindicationUtil = async (db, patientId, data, requesterId, reques
4667
4661
  };
4668
4662
  var removeContraindicationUtil = async (db, patientId, contraindicationIndex, requesterId, requesterRoles) => {
4669
4663
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4670
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4671
- if (!doc37.exists()) throw new Error("Medical info not found");
4672
- 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();
4673
4667
  if (contraindicationIndex >= medicalInfo.contraindications.length) {
4674
4668
  throw new Error("Invalid contraindication index");
4675
4669
  }
@@ -4696,9 +4690,9 @@ var updateMedicationUtil = async (db, patientId, data, requesterId, requesterRol
4696
4690
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4697
4691
  const validatedData = updateMedicationSchema.parse(data);
4698
4692
  const { medicationIndex, ...updateData } = validatedData;
4699
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4700
- if (!doc37.exists()) throw new Error("Medical info not found");
4701
- 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();
4702
4696
  if (medicationIndex >= medicalInfo.currentMedications.length) {
4703
4697
  throw new Error("Invalid medication index");
4704
4698
  }
@@ -4715,9 +4709,9 @@ var updateMedicationUtil = async (db, patientId, data, requesterId, requesterRol
4715
4709
  };
4716
4710
  var removeMedicationUtil = async (db, patientId, medicationIndex, requesterId, requesterRoles) => {
4717
4711
  await checkMedicalAccessUtil(db, patientId, requesterId, requesterRoles);
4718
- const doc37 = await getDoc10(getMedicalInfoDocRef(db, patientId));
4719
- if (!doc37.exists()) throw new Error("Medical info not found");
4720
- 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();
4721
4715
  if (medicationIndex >= medicalInfo.currentMedications.length) {
4722
4716
  throw new Error("Invalid medication index");
4723
4717
  }
@@ -5020,7 +5014,7 @@ var searchPatientsUtil = async (db, params, requester) => {
5020
5014
  const finalQuery = query8(patientsCollectionRef, ...constraints);
5021
5015
  const querySnapshot = await getDocs8(finalQuery);
5022
5016
  const patients = querySnapshot.docs.map(
5023
- (doc37) => doc37.data()
5017
+ (doc38) => doc38.data()
5024
5018
  );
5025
5019
  console.log(
5026
5020
  `[searchPatientsUtil] Found ${patients.length} patients matching criteria.`
@@ -5052,8 +5046,8 @@ var getAllPatientsUtil = async (db, options) => {
5052
5046
  }
5053
5047
  const patientsSnapshot = await getDocs8(q);
5054
5048
  const patients = [];
5055
- patientsSnapshot.forEach((doc37) => {
5056
- patients.push(doc37.data());
5049
+ patientsSnapshot.forEach((doc38) => {
5050
+ patients.push(doc38.data());
5057
5051
  });
5058
5052
  console.log(`[getAllPatientsUtil] Found ${patients.length} patients`);
5059
5053
  return patients;
@@ -5186,7 +5180,7 @@ var getActiveInviteTokensByClinicUtil = async (db, clinicId) => {
5186
5180
  if (querySnapshot.empty) {
5187
5181
  return [];
5188
5182
  }
5189
- return querySnapshot.docs.map((doc37) => doc37.data());
5183
+ return querySnapshot.docs.map((doc38) => doc38.data());
5190
5184
  };
5191
5185
  var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
5192
5186
  const tokensRef = collection9(
@@ -5204,7 +5198,7 @@ var getActiveInviteTokensByPatientUtil = async (db, patientId) => {
5204
5198
  if (querySnapshot.empty) {
5205
5199
  return [];
5206
5200
  }
5207
- return querySnapshot.docs.map((doc37) => doc37.data());
5201
+ return querySnapshot.docs.map((doc38) => doc38.data());
5208
5202
  };
5209
5203
 
5210
5204
  // src/services/patient/patient.service.ts
@@ -6493,7 +6487,7 @@ var PractitionerService = class extends BaseService {
6493
6487
  where10("expiresAt", ">", Timestamp14.now())
6494
6488
  );
6495
6489
  const querySnapshot = await getDocs10(q);
6496
- return querySnapshot.docs.map((doc37) => doc37.data());
6490
+ return querySnapshot.docs.map((doc38) => doc38.data());
6497
6491
  }
6498
6492
  /**
6499
6493
  * Gets a token by its string value and validates it
@@ -6603,7 +6597,7 @@ var PractitionerService = class extends BaseService {
6603
6597
  where10("status", "==", "active" /* ACTIVE */)
6604
6598
  );
6605
6599
  const querySnapshot = await getDocs10(q);
6606
- return querySnapshot.docs.map((doc37) => doc37.data());
6600
+ return querySnapshot.docs.map((doc38) => doc38.data());
6607
6601
  }
6608
6602
  /**
6609
6603
  * Dohvata sve zdravstvene radnike za određenu kliniku
@@ -6615,7 +6609,7 @@ var PractitionerService = class extends BaseService {
6615
6609
  where10("isActive", "==", true)
6616
6610
  );
6617
6611
  const querySnapshot = await getDocs10(q);
6618
- return querySnapshot.docs.map((doc37) => doc37.data());
6612
+ return querySnapshot.docs.map((doc38) => doc38.data());
6619
6613
  }
6620
6614
  /**
6621
6615
  * Dohvata sve draft zdravstvene radnike za određenu kliniku sa statusom DRAFT
@@ -6627,7 +6621,7 @@ var PractitionerService = class extends BaseService {
6627
6621
  where10("status", "==", "draft" /* DRAFT */)
6628
6622
  );
6629
6623
  const querySnapshot = await getDocs10(q);
6630
- return querySnapshot.docs.map((doc37) => doc37.data());
6624
+ return querySnapshot.docs.map((doc38) => doc38.data());
6631
6625
  }
6632
6626
  /**
6633
6627
  * Updates a practitioner
@@ -6842,7 +6836,7 @@ var PractitionerService = class extends BaseService {
6842
6836
  );
6843
6837
  const querySnapshot = await getDocs10(q);
6844
6838
  const practitioners = querySnapshot.docs.map(
6845
- (doc37) => doc37.data()
6839
+ (doc38) => doc38.data()
6846
6840
  );
6847
6841
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
6848
6842
  return {
@@ -6916,7 +6910,7 @@ var PractitionerService = class extends BaseService {
6916
6910
  constraints.push(limit7(filters.pagination || 10));
6917
6911
  const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
6918
6912
  const querySnapshot = await getDocs10(q);
6919
- const practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
6913
+ const practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
6920
6914
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
6921
6915
  console.log(`[PRACTITIONER_SERVICE] Strategy 1 success: ${practitioners.length} practitioners`);
6922
6916
  if (practitioners.length < (filters.pagination || 10)) {
@@ -6963,7 +6957,7 @@ var PractitionerService = class extends BaseService {
6963
6957
  }
6964
6958
  const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
6965
6959
  const querySnapshot = await getDocs10(q);
6966
- let practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
6960
+ let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
6967
6961
  if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
6968
6962
  const location = filters.location;
6969
6963
  const radiusInKm = filters.radiusInKm;
@@ -6999,7 +6993,7 @@ var PractitionerService = class extends BaseService {
6999
6993
  ];
7000
6994
  const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
7001
6995
  const querySnapshot = await getDocs10(q);
7002
- let practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
6996
+ let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
7003
6997
  practitioners = this.applyInMemoryFilters(practitioners, filters);
7004
6998
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
7005
6999
  console.log(`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`);
@@ -7020,7 +7014,7 @@ var PractitionerService = class extends BaseService {
7020
7014
  ];
7021
7015
  const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
7022
7016
  const querySnapshot = await getDocs10(q);
7023
- let practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
7017
+ let practitioners = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
7024
7018
  practitioners = this.applyInMemoryFilters(practitioners, filters);
7025
7019
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
7026
7020
  console.log(`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`);
@@ -7535,7 +7529,7 @@ var UserService = class extends BaseService {
7535
7529
  ];
7536
7530
  const q = query11(collection11(this.db, USERS_COLLECTION), ...constraints);
7537
7531
  const querySnapshot = await getDocs11(q);
7538
- const users = querySnapshot.docs.map((doc37) => doc37.data());
7532
+ const users = querySnapshot.docs.map((doc38) => doc38.data());
7539
7533
  return users.map((userData) => userSchema.parse(userData));
7540
7534
  }
7541
7535
  /**
@@ -7915,7 +7909,7 @@ async function getAllActiveGroups(db) {
7915
7909
  where12("isActive", "==", true)
7916
7910
  );
7917
7911
  const querySnapshot = await getDocs12(q);
7918
- return querySnapshot.docs.map((doc37) => doc37.data());
7912
+ return querySnapshot.docs.map((doc38) => doc38.data());
7919
7913
  }
7920
7914
  async function updateClinicGroup(db, groupId, data, app) {
7921
7915
  console.log("[CLINIC_GROUP] Updating clinic group", { groupId });
@@ -8383,7 +8377,7 @@ async function getClinicsByGroup(db, groupId) {
8383
8377
  where13("isActive", "==", true)
8384
8378
  );
8385
8379
  const querySnapshot = await getDocs13(q);
8386
- return querySnapshot.docs.map((doc37) => doc37.data());
8380
+ return querySnapshot.docs.map((doc38) => doc38.data());
8387
8381
  }
8388
8382
  async function updateClinic(db, clinicId, data, adminId, clinicAdminService, app) {
8389
8383
  console.log("[CLINIC] Starting clinic update", { clinicId, adminId });
@@ -8577,7 +8571,7 @@ async function getClinicsByAdmin(db, adminId, options = {}, clinicAdminService,
8577
8571
  }
8578
8572
  const q = query13(collection13(db, CLINICS_COLLECTION), ...constraints);
8579
8573
  const querySnapshot = await getDocs13(q);
8580
- return querySnapshot.docs.map((doc37) => doc37.data());
8574
+ return querySnapshot.docs.map((doc38) => doc38.data());
8581
8575
  }
8582
8576
  async function getActiveClinicsByAdmin(db, adminId, clinicAdminService, clinicGroupService) {
8583
8577
  return getClinicsByAdmin(
@@ -8622,11 +8616,11 @@ async function getAllClinics(db, pagination, lastDoc) {
8622
8616
  }
8623
8617
  const clinicsSnapshot = await getDocs13(clinicsQuery);
8624
8618
  const lastVisible = clinicsSnapshot.docs[clinicsSnapshot.docs.length - 1];
8625
- const clinics = clinicsSnapshot.docs.map((doc37) => {
8626
- const data = doc37.data();
8619
+ const clinics = clinicsSnapshot.docs.map((doc38) => {
8620
+ const data = doc38.data();
8627
8621
  return {
8628
8622
  ...data,
8629
- id: doc37.id
8623
+ id: doc38.id
8630
8624
  };
8631
8625
  });
8632
8626
  return {
@@ -8653,8 +8647,8 @@ async function getAllClinicsInRange(db, center, rangeInKm, pagination, lastDoc)
8653
8647
  ];
8654
8648
  const q = query13(collection13(db, CLINICS_COLLECTION), ...constraints);
8655
8649
  const querySnapshot = await getDocs13(q);
8656
- for (const doc37 of querySnapshot.docs) {
8657
- const clinic = doc37.data();
8650
+ for (const doc38 of querySnapshot.docs) {
8651
+ const clinic = doc38.data();
8658
8652
  const distance = distanceBetween2(
8659
8653
  [center.latitude, center.longitude],
8660
8654
  [clinic.location.latitude, clinic.location.longitude]
@@ -8776,8 +8770,8 @@ async function findClinicsInRadius(db, center, radiusInKm, filters) {
8776
8770
  }
8777
8771
  const q = query14(collection14(db, CLINICS_COLLECTION), ...constraints);
8778
8772
  const querySnapshot = await getDocs14(q);
8779
- for (const doc37 of querySnapshot.docs) {
8780
- const clinic = doc37.data();
8773
+ for (const doc38 of querySnapshot.docs) {
8774
+ const clinic = doc38.data();
8781
8775
  const distance = distanceBetween3(
8782
8776
  [center.latitude, center.longitude],
8783
8777
  [clinic.location.latitude, clinic.location.longitude]
@@ -8906,7 +8900,7 @@ async function getClinicsByFilters(db, filters) {
8906
8900
  constraints.push(limit9(filters.pagination || 5));
8907
8901
  const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8908
8902
  const querySnapshot = await getDocs15(q);
8909
- let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8903
+ let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
8910
8904
  clinics = applyInMemoryFilters(clinics, filters);
8911
8905
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8912
8906
  console.log(`[CLINIC_SERVICE] Strategy 1 success: ${clinics.length} clinics`);
@@ -8938,7 +8932,7 @@ async function getClinicsByFilters(db, filters) {
8938
8932
  constraints.push(limit9(filters.pagination || 5));
8939
8933
  const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8940
8934
  const querySnapshot = await getDocs15(q);
8941
- let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8935
+ let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
8942
8936
  clinics = applyInMemoryFilters(clinics, filters);
8943
8937
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8944
8938
  console.log(`[CLINIC_SERVICE] Strategy 2 success: ${clinics.length} clinics`);
@@ -8968,7 +8962,7 @@ async function getClinicsByFilters(db, filters) {
8968
8962
  constraints.push(limit9(filters.pagination || 5));
8969
8963
  const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8970
8964
  const querySnapshot = await getDocs15(q);
8971
- let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8965
+ let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
8972
8966
  clinics = applyInMemoryFilters(clinics, filters);
8973
8967
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8974
8968
  console.log(`[CLINIC_SERVICE] Strategy 3 success: ${clinics.length} clinics`);
@@ -8988,7 +8982,7 @@ async function getClinicsByFilters(db, filters) {
8988
8982
  ];
8989
8983
  const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8990
8984
  const querySnapshot = await getDocs15(q);
8991
- let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8985
+ let clinics = querySnapshot.docs.map((doc38) => ({ ...doc38.data(), id: doc38.id }));
8992
8986
  clinics = applyInMemoryFilters(clinics, filters);
8993
8987
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8994
8988
  console.log(`[CLINIC_SERVICE] Strategy 4 success: ${clinics.length} clinics`);
@@ -9564,11 +9558,11 @@ var ClinicService = class extends BaseService {
9564
9558
  async getClinicsForMap() {
9565
9559
  const clinicsRef = collection16(this.db, CLINICS_COLLECTION);
9566
9560
  const snapshot = await getDocs16(clinicsRef);
9567
- const clinicsForMap = snapshot.docs.map((doc37) => {
9561
+ const clinicsForMap = snapshot.docs.map((doc38) => {
9568
9562
  var _a, _b, _c;
9569
- const data = doc37.data();
9563
+ const data = doc38.data();
9570
9564
  return {
9571
- id: doc37.id,
9565
+ id: doc38.id,
9572
9566
  name: data.name,
9573
9567
  address: ((_a = data.location) == null ? void 0 : _a.address) || "",
9574
9568
  latitude: (_b = data.location) == null ? void 0 : _b.latitude,
@@ -10775,7 +10769,7 @@ async function updatePractitionerCalendarEventUtil(db, practitionerId, eventId,
10775
10769
  }
10776
10770
 
10777
10771
  // src/services/calendar/utils/appointment.utils.ts
10778
- async function createAppointmentUtil2(db, clinicId, practitionerId, patientId, eventData, generateId2) {
10772
+ async function createAppointmentUtil(db, clinicId, practitionerId, patientId, eventData, generateId2) {
10779
10773
  const eventId = generateId2();
10780
10774
  const autoConfirm = await checkAutoConfirmAppointmentsUtil(db, clinicId);
10781
10775
  const initialStatus = autoConfirm ? "confirmed" /* CONFIRMED */ : "pending" /* PENDING */;
@@ -10922,7 +10916,7 @@ async function searchCalendarEventsUtil(db, params) {
10922
10916
  const finalQuery = query21(collectionRef, ...constraints);
10923
10917
  const querySnapshot = await getDocs21(finalQuery);
10924
10918
  const events = querySnapshot.docs.map(
10925
- (doc37) => ({ id: doc37.id, ...doc37.data() })
10919
+ (doc38) => ({ id: doc38.id, ...doc38.data() })
10926
10920
  );
10927
10921
  return events;
10928
10922
  } catch (error) {
@@ -11015,7 +11009,7 @@ async function getPractitionerSyncedCalendarsUtil(db, practitionerId) {
11015
11009
  );
11016
11010
  const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
11017
11011
  const querySnapshot = await getDocs22(q);
11018
- return querySnapshot.docs.map((doc37) => doc37.data());
11012
+ return querySnapshot.docs.map((doc38) => doc38.data());
11019
11013
  }
11020
11014
  async function getPatientSyncedCalendarUtil(db, patientId, calendarId) {
11021
11015
  const calendarRef = getPatientSyncedCalendarDocRef(db, patientId, calendarId);
@@ -11032,7 +11026,7 @@ async function getPatientSyncedCalendarsUtil(db, patientId) {
11032
11026
  );
11033
11027
  const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
11034
11028
  const querySnapshot = await getDocs22(q);
11035
- return querySnapshot.docs.map((doc37) => doc37.data());
11029
+ return querySnapshot.docs.map((doc38) => doc38.data());
11036
11030
  }
11037
11031
  async function getClinicSyncedCalendarUtil(db, clinicId, calendarId) {
11038
11032
  const calendarRef = getClinicSyncedCalendarDocRef(db, clinicId, calendarId);
@@ -11049,7 +11043,7 @@ async function getClinicSyncedCalendarsUtil(db, clinicId) {
11049
11043
  );
11050
11044
  const q = query22(calendarsRef, orderBy11("createdAt", "desc"));
11051
11045
  const querySnapshot = await getDocs22(q);
11052
- return querySnapshot.docs.map((doc37) => doc37.data());
11046
+ return querySnapshot.docs.map((doc38) => doc38.data());
11053
11047
  }
11054
11048
  async function updatePractitionerSyncedCalendarUtil(db, practitionerId, calendarId, updateData) {
11055
11049
  const calendarRef = getPractitionerSyncedCalendarDocRef(
@@ -12117,7 +12111,7 @@ var CalendarServiceV2 = class extends BaseService {
12117
12111
  syncStatus: "internal" /* INTERNAL */,
12118
12112
  eventType: "appointment" /* APPOINTMENT */
12119
12113
  };
12120
- const appointment = await createAppointmentUtil2(
12114
+ const appointment = await createAppointmentUtil(
12121
12115
  this.db,
12122
12116
  params.clinicId,
12123
12117
  params.doctorId,
@@ -12404,9 +12398,9 @@ var CalendarServiceV2 = class extends BaseService {
12404
12398
  where23("eventTime.start", "<=", Timestamp26.fromDate(endDate))
12405
12399
  );
12406
12400
  const eventsSnapshot = await getDocs23(q);
12407
- const events = eventsSnapshot.docs.map((doc37) => ({
12408
- id: doc37.id,
12409
- ...doc37.data()
12401
+ const events = eventsSnapshot.docs.map((doc38) => ({
12402
+ id: doc38.id,
12403
+ ...doc38.data()
12410
12404
  }));
12411
12405
  const calendars = await this.syncedCalendarsService.getPractitionerSyncedCalendars(
12412
12406
  doctorId
@@ -13040,7 +13034,7 @@ var CalendarServiceV2 = class extends BaseService {
13040
13034
  ])
13041
13035
  );
13042
13036
  const querySnapshot = await getDocs23(q);
13043
- return querySnapshot.docs.map((doc37) => doc37.data());
13037
+ return querySnapshot.docs.map((doc38) => doc38.data());
13044
13038
  }
13045
13039
  /**
13046
13040
  * Calculates available time slots based on working hours, schedule and existing appointments
@@ -13585,7 +13579,7 @@ var PractitionerInviteService = class extends BaseService {
13585
13579
  ...constraints
13586
13580
  );
13587
13581
  const querySnapshot = await getDocs24(q);
13588
- return querySnapshot.docs.map((doc37) => doc37.data());
13582
+ return querySnapshot.docs.map((doc38) => doc38.data());
13589
13583
  } catch (error) {
13590
13584
  console.error(
13591
13585
  "[PractitionerInviteService] Error getting doctor invites:",
@@ -13614,7 +13608,7 @@ var PractitionerInviteService = class extends BaseService {
13614
13608
  ...constraints
13615
13609
  );
13616
13610
  const querySnapshot = await getDocs24(q);
13617
- return querySnapshot.docs.map((doc37) => doc37.data());
13611
+ return querySnapshot.docs.map((doc38) => doc38.data());
13618
13612
  } catch (error) {
13619
13613
  console.error(
13620
13614
  "[PractitionerInviteService] Error getting clinic invites:",
@@ -13770,7 +13764,7 @@ var PractitionerInviteService = class extends BaseService {
13770
13764
  );
13771
13765
  const querySnapshot = await getDocs24(q);
13772
13766
  let invites = querySnapshot.docs.map(
13773
- (doc37) => doc37.data()
13767
+ (doc38) => doc38.data()
13774
13768
  );
13775
13769
  if (filters.fromDate) {
13776
13770
  invites = invites.filter(
@@ -13886,9 +13880,10 @@ import {
13886
13880
  limit as limit12,
13887
13881
  startAfter as startAfter10
13888
13882
  } from "firebase/firestore";
13883
+ import { getCountFromServer } from "firebase/firestore";
13889
13884
  var DocumentationTemplateService = class extends BaseService {
13890
- constructor() {
13891
- super(...arguments);
13885
+ constructor(...args) {
13886
+ super(...args);
13892
13887
  this.collectionRef = collection25(
13893
13888
  this.db,
13894
13889
  DOCUMENTATION_TEMPLATES_COLLECTION
@@ -14040,8 +14035,8 @@ var DocumentationTemplateService = class extends BaseService {
14040
14035
  const q = query25(versionsCollectionRef, orderBy13("version", "desc"));
14041
14036
  const querySnapshot = await getDocs25(q);
14042
14037
  const versions = [];
14043
- querySnapshot.forEach((doc37) => {
14044
- versions.push(doc37.data());
14038
+ querySnapshot.forEach((doc38) => {
14039
+ versions.push(doc38.data());
14045
14040
  });
14046
14041
  return versions;
14047
14042
  }
@@ -14072,15 +14067,97 @@ var DocumentationTemplateService = class extends BaseService {
14072
14067
  const querySnapshot = await getDocs25(q);
14073
14068
  const templates = [];
14074
14069
  let lastVisible = null;
14075
- querySnapshot.forEach((doc37) => {
14076
- templates.push(doc37.data());
14077
- 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;
14078
14117
  });
14079
14118
  return {
14080
14119
  templates,
14081
14120
  lastDoc: lastVisible
14082
14121
  };
14083
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
+ }
14084
14161
  /**
14085
14162
  * Get templates by tags
14086
14163
  * @param tags - Tags to filter by
@@ -14102,9 +14179,9 @@ var DocumentationTemplateService = class extends BaseService {
14102
14179
  const querySnapshot = await getDocs25(q);
14103
14180
  const templates = [];
14104
14181
  let lastVisible = null;
14105
- querySnapshot.forEach((doc37) => {
14106
- templates.push(doc37.data());
14107
- lastVisible = doc37;
14182
+ querySnapshot.forEach((doc38) => {
14183
+ templates.push(doc38.data());
14184
+ lastVisible = doc38;
14108
14185
  });
14109
14186
  return {
14110
14187
  templates,
@@ -14131,9 +14208,9 @@ var DocumentationTemplateService = class extends BaseService {
14131
14208
  const querySnapshot = await getDocs25(q);
14132
14209
  const templates = [];
14133
14210
  let lastVisible = null;
14134
- querySnapshot.forEach((doc37) => {
14135
- templates.push(doc37.data());
14136
- lastVisible = doc37;
14211
+ querySnapshot.forEach((doc38) => {
14212
+ templates.push(doc38.data());
14213
+ lastVisible = doc38;
14137
14214
  });
14138
14215
  return {
14139
14216
  templates,
@@ -14159,8 +14236,8 @@ var DocumentationTemplateService = class extends BaseService {
14159
14236
  }
14160
14237
  const querySnapshot = await getDocs25(q);
14161
14238
  const templates = [];
14162
- querySnapshot.forEach((doc37) => {
14163
- templates.push(doc37.data());
14239
+ querySnapshot.forEach((doc38) => {
14240
+ templates.push(doc38.data());
14164
14241
  });
14165
14242
  return templates;
14166
14243
  }
@@ -14366,9 +14443,9 @@ var FilledDocumentService = class extends BaseService {
14366
14443
  const querySnapshot = await getDocs26(q);
14367
14444
  const documents = [];
14368
14445
  let lastVisible = null;
14369
- querySnapshot.forEach((doc37) => {
14370
- documents.push(doc37.data());
14371
- lastVisible = doc37;
14446
+ querySnapshot.forEach((doc38) => {
14447
+ documents.push(doc38.data());
14448
+ lastVisible = doc38;
14372
14449
  });
14373
14450
  return {
14374
14451
  documents,
@@ -14590,9 +14667,9 @@ var NotificationService = class extends BaseService {
14590
14667
  orderBy15("notificationTime", "desc")
14591
14668
  );
14592
14669
  const querySnapshot = await getDocs27(q);
14593
- return querySnapshot.docs.map((doc37) => ({
14594
- id: doc37.id,
14595
- ...doc37.data()
14670
+ return querySnapshot.docs.map((doc38) => ({
14671
+ id: doc38.id,
14672
+ ...doc38.data()
14596
14673
  }));
14597
14674
  }
14598
14675
  /**
@@ -14606,9 +14683,9 @@ var NotificationService = class extends BaseService {
14606
14683
  orderBy15("notificationTime", "desc")
14607
14684
  );
14608
14685
  const querySnapshot = await getDocs27(q);
14609
- return querySnapshot.docs.map((doc37) => ({
14610
- id: doc37.id,
14611
- ...doc37.data()
14686
+ return querySnapshot.docs.map((doc38) => ({
14687
+ id: doc38.id,
14688
+ ...doc38.data()
14612
14689
  }));
14613
14690
  }
14614
14691
  /**
@@ -14680,9 +14757,9 @@ var NotificationService = class extends BaseService {
14680
14757
  orderBy15("notificationTime", "desc")
14681
14758
  );
14682
14759
  const querySnapshot = await getDocs27(q);
14683
- return querySnapshot.docs.map((doc37) => ({
14684
- id: doc37.id,
14685
- ...doc37.data()
14760
+ return querySnapshot.docs.map((doc38) => ({
14761
+ id: doc38.id,
14762
+ ...doc38.data()
14686
14763
  }));
14687
14764
  }
14688
14765
  /**
@@ -14695,9 +14772,9 @@ var NotificationService = class extends BaseService {
14695
14772
  orderBy15("notificationTime", "desc")
14696
14773
  );
14697
14774
  const querySnapshot = await getDocs27(q);
14698
- return querySnapshot.docs.map((doc37) => ({
14699
- id: doc37.id,
14700
- ...doc37.data()
14775
+ return querySnapshot.docs.map((doc38) => ({
14776
+ id: doc38.id,
14777
+ ...doc38.data()
14701
14778
  }));
14702
14779
  }
14703
14780
  };
@@ -15001,7 +15078,9 @@ var ProcedureService = class extends BaseService {
15001
15078
  return media;
15002
15079
  }
15003
15080
  if (media instanceof File || media instanceof Blob) {
15004
- console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
15081
+ console.log(
15082
+ `[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
15083
+ );
15005
15084
  const metadata = await this.mediaService.uploadMedia(
15006
15085
  media,
15007
15086
  ownerId,
@@ -15023,7 +15102,11 @@ var ProcedureService = class extends BaseService {
15023
15102
  if (!mediaArray || mediaArray.length === 0) return [];
15024
15103
  const result = [];
15025
15104
  for (const media of mediaArray) {
15026
- const processedUrl = await this.processMedia(media, ownerId, collectionName);
15105
+ const processedUrl = await this.processMedia(
15106
+ media,
15107
+ ownerId,
15108
+ collectionName
15109
+ );
15027
15110
  if (processedUrl) {
15028
15111
  result.push(processedUrl);
15029
15112
  }
@@ -15036,28 +15119,46 @@ var ProcedureService = class extends BaseService {
15036
15119
  * @returns The created procedure
15037
15120
  */
15038
15121
  async createProcedure(data) {
15039
- var _a;
15122
+ var _a, _b, _c;
15040
15123
  const validatedData = createProcedureSchema.parse(data);
15041
15124
  const procedureId = this.generateId();
15042
15125
  const [category, subcategory, technology, product] = await Promise.all([
15043
15126
  this.categoryService.getById(validatedData.categoryId),
15044
- this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
15127
+ this.subcategoryService.getById(
15128
+ validatedData.categoryId,
15129
+ validatedData.subcategoryId
15130
+ ),
15045
15131
  this.technologyService.getById(validatedData.technologyId),
15046
- this.productService.getById(validatedData.technologyId, validatedData.productId)
15132
+ this.productService.getById(
15133
+ validatedData.technologyId,
15134
+ validatedData.productId
15135
+ )
15047
15136
  ]);
15048
15137
  if (!category || !subcategory || !technology || !product) {
15049
15138
  throw new Error("One or more required base entities not found");
15050
15139
  }
15051
- const clinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
15140
+ const clinicRef = doc30(
15141
+ this.db,
15142
+ CLINICS_COLLECTION,
15143
+ validatedData.clinicBranchId
15144
+ );
15052
15145
  const clinicSnapshot = await getDoc32(clinicRef);
15053
15146
  if (!clinicSnapshot.exists()) {
15054
- throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
15147
+ throw new Error(
15148
+ `Clinic with ID ${validatedData.clinicBranchId} not found`
15149
+ );
15055
15150
  }
15056
15151
  const clinic = clinicSnapshot.data();
15057
- const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
15152
+ const practitionerRef = doc30(
15153
+ this.db,
15154
+ PRACTITIONERS_COLLECTION,
15155
+ validatedData.practitionerId
15156
+ );
15058
15157
  const practitionerSnapshot = await getDoc32(practitionerRef);
15059
15158
  if (!practitionerSnapshot.exists()) {
15060
- throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
15159
+ throw new Error(
15160
+ `Practitioner with ID ${validatedData.practitionerId} not found`
15161
+ );
15061
15162
  }
15062
15163
  const practitioner = practitionerSnapshot.data();
15063
15164
  let processedPhotos = [];
@@ -15098,7 +15199,9 @@ var ProcedureService = class extends BaseService {
15098
15199
  product,
15099
15200
  blockingConditions: technology.blockingConditions,
15100
15201
  contraindications: technology.contraindications || [],
15202
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
15101
15203
  treatmentBenefits: technology.benefits,
15204
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
15102
15205
  preRequirements: technology.requirements.pre,
15103
15206
  postRequirements: technology.requirements.post,
15104
15207
  certificationRequirement: technology.certificationRequirement,
@@ -15139,7 +15242,7 @@ var ProcedureService = class extends BaseService {
15139
15242
  * @returns A promise that resolves to an array of the newly created procedures.
15140
15243
  */
15141
15244
  async bulkCreateProcedures(baseData, practitionerIds) {
15142
- var _a;
15245
+ var _a, _b, _c;
15143
15246
  if (!practitionerIds || practitionerIds.length === 0) {
15144
15247
  throw new Error("Practitioner IDs array cannot be empty.");
15145
15248
  }
@@ -15147,16 +15250,24 @@ var ProcedureService = class extends BaseService {
15147
15250
  const validatedData = createProcedureSchema.parse(validationData);
15148
15251
  const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
15149
15252
  this.categoryService.getById(validatedData.categoryId),
15150
- this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
15253
+ this.subcategoryService.getById(
15254
+ validatedData.categoryId,
15255
+ validatedData.subcategoryId
15256
+ ),
15151
15257
  this.technologyService.getById(validatedData.technologyId),
15152
- this.productService.getById(validatedData.technologyId, validatedData.productId),
15258
+ this.productService.getById(
15259
+ validatedData.technologyId,
15260
+ validatedData.productId
15261
+ ),
15153
15262
  getDoc32(doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
15154
15263
  ]);
15155
15264
  if (!category || !subcategory || !technology || !product) {
15156
15265
  throw new Error("One or more required base entities not found");
15157
15266
  }
15158
15267
  if (!clinicSnapshot.exists()) {
15159
- throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
15268
+ throw new Error(
15269
+ `Clinic with ID ${validatedData.clinicBranchId} not found`
15270
+ );
15160
15271
  }
15161
15272
  const clinic = clinicSnapshot.data();
15162
15273
  let processedPhotos = [];
@@ -15176,14 +15287,18 @@ var ProcedureService = class extends BaseService {
15176
15287
  where29(documentId2(), "in", chunk)
15177
15288
  );
15178
15289
  const practitionersSnapshot = await getDocs29(practitionersQuery);
15179
- practitionersSnapshot.docs.forEach((doc37) => {
15180
- practitionersMap.set(doc37.id, doc37.data());
15290
+ practitionersSnapshot.docs.forEach((doc38) => {
15291
+ practitionersMap.set(doc38.id, doc38.data());
15181
15292
  });
15182
15293
  }
15183
15294
  if (practitionersMap.size !== practitionerIds.length) {
15184
15295
  const foundIds = Array.from(practitionersMap.keys());
15185
- const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
15186
- 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
+ );
15187
15302
  }
15188
15303
  const batch = writeBatch6(this.db);
15189
15304
  const createdProcedureIds = [];
@@ -15221,7 +15336,9 @@ var ProcedureService = class extends BaseService {
15221
15336
  product,
15222
15337
  blockingConditions: technology.blockingConditions,
15223
15338
  contraindications: technology.contraindications || [],
15339
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
15224
15340
  treatmentBenefits: technology.benefits,
15341
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
15225
15342
  preRequirements: technology.requirements.pre,
15226
15343
  postRequirements: technology.requirements.post,
15227
15344
  certificationRequirement: technology.certificationRequirement,
@@ -15251,10 +15368,13 @@ var ProcedureService = class extends BaseService {
15251
15368
  const fetchedProcedures = [];
15252
15369
  for (let i = 0; i < createdProcedureIds.length; i += 30) {
15253
15370
  const chunk = createdProcedureIds.slice(i, i + 30);
15254
- 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
+ );
15255
15375
  const snapshot = await getDocs29(q);
15256
- snapshot.forEach((doc37) => {
15257
- fetchedProcedures.push(doc37.data());
15376
+ snapshot.forEach((doc38) => {
15377
+ fetchedProcedures.push(doc38.data());
15258
15378
  });
15259
15379
  }
15260
15380
  return fetchedProcedures;
@@ -15284,7 +15404,7 @@ var ProcedureService = class extends BaseService {
15284
15404
  where29("isActive", "==", true)
15285
15405
  );
15286
15406
  const snapshot = await getDocs29(q);
15287
- return snapshot.docs.map((doc37) => doc37.data());
15407
+ return snapshot.docs.map((doc38) => doc38.data());
15288
15408
  }
15289
15409
  /**
15290
15410
  * Gets all procedures for a practitioner
@@ -15298,7 +15418,7 @@ var ProcedureService = class extends BaseService {
15298
15418
  where29("isActive", "==", true)
15299
15419
  );
15300
15420
  const snapshot = await getDocs29(q);
15301
- return snapshot.docs.map((doc37) => doc37.data());
15421
+ return snapshot.docs.map((doc38) => doc38.data());
15302
15422
  }
15303
15423
  /**
15304
15424
  * Gets all inactive procedures for a practitioner
@@ -15312,7 +15432,7 @@ var ProcedureService = class extends BaseService {
15312
15432
  where29("isActive", "==", false)
15313
15433
  );
15314
15434
  const snapshot = await getDocs29(q);
15315
- return snapshot.docs.map((doc37) => doc37.data());
15435
+ return snapshot.docs.map((doc38) => doc38.data());
15316
15436
  }
15317
15437
  /**
15318
15438
  * Updates a procedure
@@ -15321,7 +15441,7 @@ var ProcedureService = class extends BaseService {
15321
15441
  * @returns The updated procedure
15322
15442
  */
15323
15443
  async updateProcedure(id, data) {
15324
- var _a;
15444
+ var _a, _b, _c;
15325
15445
  const validatedData = updateProcedureSchema.parse(data);
15326
15446
  const procedureRef = doc30(this.db, PROCEDURES_COLLECTION, id);
15327
15447
  const procedureSnapshot = await getDoc32(procedureRef);
@@ -15352,7 +15472,9 @@ var ProcedureService = class extends BaseService {
15352
15472
  );
15353
15473
  const newPractitionerSnap = await getDoc32(newPractitionerRef);
15354
15474
  if (!newPractitionerSnap.exists())
15355
- throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
15475
+ throw new Error(
15476
+ `New Practitioner ${validatedData.practitionerId} not found`
15477
+ );
15356
15478
  newPractitioner = newPractitionerSnap.data();
15357
15479
  updatedProcedureData.doctorInfo = {
15358
15480
  id: newPractitioner.id,
@@ -15366,7 +15488,11 @@ var ProcedureService = class extends BaseService {
15366
15488
  }
15367
15489
  if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
15368
15490
  clinicChanged = true;
15369
- const newClinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
15491
+ const newClinicRef = doc30(
15492
+ this.db,
15493
+ CLINICS_COLLECTION,
15494
+ validatedData.clinicBranchId
15495
+ );
15370
15496
  const newClinicSnap = await getDoc32(newClinicRef);
15371
15497
  if (!newClinicSnap.exists())
15372
15498
  throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
@@ -15385,8 +15511,11 @@ var ProcedureService = class extends BaseService {
15385
15511
  updatedProcedureData.nameLower = validatedData.name.toLowerCase();
15386
15512
  }
15387
15513
  if (validatedData.categoryId) {
15388
- const category = await this.categoryService.getById(validatedData.categoryId);
15389
- 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`);
15390
15519
  updatedProcedureData.category = category;
15391
15520
  finalCategoryId = category.id;
15392
15521
  }
@@ -15401,23 +15530,34 @@ var ProcedureService = class extends BaseService {
15401
15530
  );
15402
15531
  updatedProcedureData.subcategory = subcategory;
15403
15532
  } else if (validatedData.subcategoryId) {
15404
- console.warn("Attempted to update subcategory without a valid categoryId");
15533
+ console.warn(
15534
+ "Attempted to update subcategory without a valid categoryId"
15535
+ );
15405
15536
  }
15406
15537
  let finalTechnologyId = existingProcedure.technology.id;
15407
15538
  if (validatedData.technologyId) {
15408
- const technology = await this.technologyService.getById(validatedData.technologyId);
15409
- 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`);
15410
15544
  updatedProcedureData.technology = technology;
15411
15545
  finalTechnologyId = technology.id;
15412
15546
  updatedProcedureData.blockingConditions = technology.blockingConditions;
15547
+ updatedProcedureData.contraindications = technology.contraindications || [];
15548
+ updatedProcedureData.contraindicationIds = ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [];
15413
15549
  updatedProcedureData.treatmentBenefits = technology.benefits;
15550
+ updatedProcedureData.treatmentBenefitIds = ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [];
15414
15551
  updatedProcedureData.preRequirements = technology.requirements.pre;
15415
15552
  updatedProcedureData.postRequirements = technology.requirements.post;
15416
15553
  updatedProcedureData.certificationRequirement = technology.certificationRequirement;
15417
15554
  updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
15418
15555
  }
15419
15556
  if (validatedData.productId && finalTechnologyId) {
15420
- const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
15557
+ const product = await this.productService.getById(
15558
+ finalTechnologyId,
15559
+ validatedData.productId
15560
+ );
15421
15561
  if (!product)
15422
15562
  throw new Error(
15423
15563
  `Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
@@ -15489,28 +15629,32 @@ var ProcedureService = class extends BaseService {
15489
15629
  const proceduresCollection = collection29(this.db, PROCEDURES_COLLECTION);
15490
15630
  let proceduresQuery = query29(proceduresCollection);
15491
15631
  if (pagination && pagination > 0) {
15492
- const { limit: limit16, startAfter: startAfter14 } = await import("firebase/firestore");
15632
+ const { limit: limit21, startAfter: startAfter19 } = await import("firebase/firestore");
15493
15633
  if (lastDoc) {
15494
15634
  proceduresQuery = query29(
15495
15635
  proceduresCollection,
15496
15636
  orderBy17("name"),
15497
15637
  // Use imported orderBy
15498
- startAfter14(lastDoc),
15499
- limit16(pagination)
15638
+ startAfter19(lastDoc),
15639
+ limit21(pagination)
15500
15640
  );
15501
15641
  } else {
15502
- proceduresQuery = query29(proceduresCollection, orderBy17("name"), limit16(pagination));
15642
+ proceduresQuery = query29(
15643
+ proceduresCollection,
15644
+ orderBy17("name"),
15645
+ limit21(pagination)
15646
+ );
15503
15647
  }
15504
15648
  } else {
15505
15649
  proceduresQuery = query29(proceduresCollection, orderBy17("name"));
15506
15650
  }
15507
15651
  const proceduresSnapshot = await getDocs29(proceduresQuery);
15508
15652
  const lastVisible = proceduresSnapshot.docs[proceduresSnapshot.docs.length - 1];
15509
- const procedures = proceduresSnapshot.docs.map((doc37) => {
15510
- const data = doc37.data();
15653
+ const procedures = proceduresSnapshot.docs.map((doc38) => {
15654
+ const data = doc38.data();
15511
15655
  return {
15512
15656
  ...data,
15513
- id: doc37.id
15657
+ id: doc38.id
15514
15658
  // Ensure ID is present
15515
15659
  };
15516
15660
  });
@@ -15530,7 +15674,7 @@ var ProcedureService = class extends BaseService {
15530
15674
  *
15531
15675
  * @param filters - Various filters to apply
15532
15676
  * @param filters.nameSearch - Optional search text for procedure name
15533
- * @param filters.treatmentBenefits - Optional array of treatment benefits to filter by
15677
+ * @param filters.treatmentBenefitIds - Optional array of treatment benefits to filter by
15534
15678
  * @param filters.procedureFamily - Optional procedure family to filter by
15535
15679
  * @param filters.procedureCategory - Optional procedure category to filter by
15536
15680
  * @param filters.procedureSubcategory - Optional procedure subcategory to filter by
@@ -15548,7 +15692,9 @@ var ProcedureService = class extends BaseService {
15548
15692
  */
15549
15693
  async getProceduresByFilters(filters) {
15550
15694
  try {
15551
- console.log("[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies");
15695
+ console.log(
15696
+ "[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies"
15697
+ );
15552
15698
  if (filters.location && filters.radiusInKm) {
15553
15699
  console.log("[PROCEDURE_SERVICE] Executing geo query:", {
15554
15700
  location: filters.location,
@@ -15556,7 +15702,10 @@ var ProcedureService = class extends BaseService {
15556
15702
  serviceName: "ProcedureService"
15557
15703
  });
15558
15704
  if (!filters.location.latitude || !filters.location.longitude) {
15559
- console.warn("[PROCEDURE_SERVICE] Invalid location data:", filters.location);
15705
+ console.warn(
15706
+ "[PROCEDURE_SERVICE] Invalid location data:",
15707
+ filters.location
15708
+ );
15560
15709
  filters.location = void 0;
15561
15710
  filters.radiusInKm = void 0;
15562
15711
  }
@@ -15576,13 +15725,19 @@ var ProcedureService = class extends BaseService {
15576
15725
  constraints.push(where29("family", "==", filters.procedureFamily));
15577
15726
  }
15578
15727
  if (filters.procedureCategory) {
15579
- constraints.push(where29("category.id", "==", filters.procedureCategory));
15728
+ constraints.push(
15729
+ where29("category.id", "==", filters.procedureCategory)
15730
+ );
15580
15731
  }
15581
15732
  if (filters.procedureSubcategory) {
15582
- constraints.push(where29("subcategory.id", "==", filters.procedureSubcategory));
15733
+ constraints.push(
15734
+ where29("subcategory.id", "==", filters.procedureSubcategory)
15735
+ );
15583
15736
  }
15584
15737
  if (filters.procedureTechnology) {
15585
- constraints.push(where29("technology.id", "==", filters.procedureTechnology));
15738
+ constraints.push(
15739
+ where29("technology.id", "==", filters.procedureTechnology)
15740
+ );
15586
15741
  }
15587
15742
  if (filters.minPrice !== void 0) {
15588
15743
  constraints.push(where29("price", ">=", filters.minPrice));
@@ -15591,20 +15746,32 @@ var ProcedureService = class extends BaseService {
15591
15746
  constraints.push(where29("price", "<=", filters.maxPrice));
15592
15747
  }
15593
15748
  if (filters.minRating !== void 0) {
15594
- constraints.push(where29("reviewInfo.averageRating", ">=", filters.minRating));
15749
+ constraints.push(
15750
+ where29("reviewInfo.averageRating", ">=", filters.minRating)
15751
+ );
15595
15752
  }
15596
15753
  if (filters.maxRating !== void 0) {
15597
- constraints.push(where29("reviewInfo.averageRating", "<=", filters.maxRating));
15754
+ constraints.push(
15755
+ where29("reviewInfo.averageRating", "<=", filters.maxRating)
15756
+ );
15598
15757
  }
15599
15758
  if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
15600
- const benefitsToMatch = filters.treatmentBenefits;
15601
- 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
+ );
15602
15767
  }
15603
15768
  return constraints;
15604
15769
  };
15605
15770
  if (filters.nameSearch && filters.nameSearch.trim()) {
15606
15771
  try {
15607
- console.log("[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search");
15772
+ console.log(
15773
+ "[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search"
15774
+ );
15608
15775
  const searchTerm = filters.nameSearch.trim().toLowerCase();
15609
15776
  const constraints = getBaseConstraints();
15610
15777
  constraints.push(where29("nameLower", ">=", searchTerm));
@@ -15620,13 +15787,18 @@ var ProcedureService = class extends BaseService {
15620
15787
  }
15621
15788
  }
15622
15789
  constraints.push(limit15(filters.pagination || 10));
15623
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15790
+ const q = query29(
15791
+ collection29(this.db, PROCEDURES_COLLECTION),
15792
+ ...constraints
15793
+ );
15624
15794
  const querySnapshot = await getDocs29(q);
15625
15795
  const procedures = querySnapshot.docs.map(
15626
- (doc37) => ({ ...doc37.data(), id: doc37.id })
15796
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
15627
15797
  );
15628
15798
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15629
- console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
15799
+ console.log(
15800
+ `[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`
15801
+ );
15630
15802
  if (procedures.length < (filters.pagination || 10)) {
15631
15803
  return { procedures, lastDoc: null };
15632
15804
  }
@@ -15637,7 +15809,9 @@ var ProcedureService = class extends BaseService {
15637
15809
  }
15638
15810
  if (filters.nameSearch && filters.nameSearch.trim()) {
15639
15811
  try {
15640
- console.log("[PROCEDURE_SERVICE] Strategy 2: Trying name field search");
15812
+ console.log(
15813
+ "[PROCEDURE_SERVICE] Strategy 2: Trying name field search"
15814
+ );
15641
15815
  const searchTerm = filters.nameSearch.trim().toLowerCase();
15642
15816
  const constraints = getBaseConstraints();
15643
15817
  constraints.push(where29("name", ">=", searchTerm));
@@ -15653,13 +15827,18 @@ var ProcedureService = class extends BaseService {
15653
15827
  }
15654
15828
  }
15655
15829
  constraints.push(limit15(filters.pagination || 10));
15656
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15830
+ const q = query29(
15831
+ collection29(this.db, PROCEDURES_COLLECTION),
15832
+ ...constraints
15833
+ );
15657
15834
  const querySnapshot = await getDocs29(q);
15658
15835
  const procedures = querySnapshot.docs.map(
15659
- (doc37) => ({ ...doc37.data(), id: doc37.id })
15836
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
15660
15837
  );
15661
15838
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15662
- console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
15839
+ console.log(
15840
+ `[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`
15841
+ );
15663
15842
  if (procedures.length < (filters.pagination || 10)) {
15664
15843
  return { procedures, lastDoc: null };
15665
15844
  }
@@ -15684,14 +15863,19 @@ var ProcedureService = class extends BaseService {
15684
15863
  }
15685
15864
  }
15686
15865
  constraints.push(limit15(filters.pagination || 10));
15687
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15866
+ const q = query29(
15867
+ collection29(this.db, PROCEDURES_COLLECTION),
15868
+ ...constraints
15869
+ );
15688
15870
  const querySnapshot = await getDocs29(q);
15689
15871
  let procedures = querySnapshot.docs.map(
15690
- (doc37) => ({ ...doc37.data(), id: doc37.id })
15872
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
15691
15873
  );
15692
15874
  procedures = this.applyInMemoryFilters(procedures, filters);
15693
15875
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15694
- console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
15876
+ console.log(
15877
+ `[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`
15878
+ );
15695
15879
  if (procedures.length < (filters.pagination || 10)) {
15696
15880
  return { procedures, lastDoc: null };
15697
15881
  }
@@ -15706,14 +15890,19 @@ var ProcedureService = class extends BaseService {
15706
15890
  orderBy17("createdAt", "desc"),
15707
15891
  limit15(filters.pagination || 10)
15708
15892
  ];
15709
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15893
+ const q = query29(
15894
+ collection29(this.db, PROCEDURES_COLLECTION),
15895
+ ...constraints
15896
+ );
15710
15897
  const querySnapshot = await getDocs29(q);
15711
15898
  let procedures = querySnapshot.docs.map(
15712
- (doc37) => ({ ...doc37.data(), id: doc37.id })
15899
+ (doc38) => ({ ...doc38.data(), id: doc38.id })
15713
15900
  );
15714
15901
  procedures = this.applyInMemoryFilters(procedures, filters);
15715
15902
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15716
- console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
15903
+ console.log(
15904
+ `[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`
15905
+ );
15717
15906
  if (procedures.length < (filters.pagination || 10)) {
15718
15907
  return { procedures, lastDoc: null };
15719
15908
  }
@@ -15721,7 +15910,9 @@ var ProcedureService = class extends BaseService {
15721
15910
  } catch (error) {
15722
15911
  console.log("[PROCEDURE_SERVICE] Strategy 4 failed:", error);
15723
15912
  }
15724
- console.log("[PROCEDURE_SERVICE] All strategies failed, returning empty result");
15913
+ console.log(
15914
+ "[PROCEDURE_SERVICE] All strategies failed, returning empty result"
15915
+ );
15725
15916
  return { procedures: [], lastDoc: null };
15726
15917
  } catch (error) {
15727
15918
  console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
@@ -15741,13 +15932,17 @@ var ProcedureService = class extends BaseService {
15741
15932
  const nameLower = procedure.nameLower || "";
15742
15933
  return name.includes(searchTerm) || nameLower.includes(searchTerm);
15743
15934
  });
15744
- console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`);
15935
+ console.log(
15936
+ `[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`
15937
+ );
15745
15938
  }
15746
15939
  if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
15747
15940
  filteredProcedures = filteredProcedures.filter((procedure) => {
15748
15941
  const price = procedure.price || 0;
15749
- if (filters.minPrice !== void 0 && price < filters.minPrice) return false;
15750
- 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;
15751
15946
  return true;
15752
15947
  });
15753
15948
  console.log(
@@ -15758,8 +15953,10 @@ var ProcedureService = class extends BaseService {
15758
15953
  filteredProcedures = filteredProcedures.filter((procedure) => {
15759
15954
  var _a;
15760
15955
  const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
15761
- if (filters.minRating !== void 0 && rating < filters.minRating) return false;
15762
- 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;
15763
15960
  return true;
15764
15961
  });
15765
15962
  console.log(
@@ -15767,10 +15964,12 @@ var ProcedureService = class extends BaseService {
15767
15964
  );
15768
15965
  }
15769
15966
  if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
15770
- const benefitsToMatch = filters.treatmentBenefits;
15967
+ const benefitIdsToMatch = filters.treatmentBenefits;
15771
15968
  filteredProcedures = filteredProcedures.filter((procedure) => {
15772
- const procedureBenefits = procedure.treatmentBenefits || [];
15773
- return benefitsToMatch.some((benefit) => procedureBenefits.includes(benefit));
15969
+ const procedureBenefitIds = procedure.treatmentBenefitIds || [];
15970
+ return benefitIdsToMatch.some(
15971
+ (benefitId) => procedureBenefitIds.includes(benefitId)
15972
+ );
15774
15973
  });
15775
15974
  console.log(
15776
15975
  `[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
@@ -15833,8 +16032,12 @@ var ProcedureService = class extends BaseService {
15833
16032
  procedure.distance = distance;
15834
16033
  return distance <= radiusInKm;
15835
16034
  });
15836
- console.log(`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`);
15837
- 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
+ );
15838
16041
  }
15839
16042
  return filteredProcedures;
15840
16043
  }
@@ -15846,19 +16049,30 @@ var ProcedureService = class extends BaseService {
15846
16049
  if (!location || !radiusInKm) {
15847
16050
  return Promise.resolve({ procedures: [], lastDoc: null });
15848
16051
  }
15849
- const bounds = geohashQueryBounds5([location.latitude, location.longitude], radiusInKm * 1e3);
16052
+ const bounds = geohashQueryBounds5(
16053
+ [location.latitude, location.longitude],
16054
+ radiusInKm * 1e3
16055
+ );
15850
16056
  const fetches = bounds.map((b) => {
15851
16057
  const constraints = [
15852
16058
  where29("clinicInfo.location.geohash", ">=", b[0]),
15853
16059
  where29("clinicInfo.location.geohash", "<=", b[1]),
15854
- where29("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
16060
+ where29(
16061
+ "isActive",
16062
+ "==",
16063
+ filters.isActive !== void 0 ? filters.isActive : true
16064
+ )
15855
16065
  ];
15856
- return getDocs29(query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints));
16066
+ return getDocs29(
16067
+ query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints)
16068
+ );
15857
16069
  });
15858
16070
  return Promise.all(fetches).then((snaps) => {
15859
16071
  const collected = [];
15860
16072
  snaps.forEach((snap) => {
15861
- 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
+ );
15862
16076
  });
15863
16077
  const uniqueMap = /* @__PURE__ */ new Map();
15864
16078
  for (const p of collected) {
@@ -15869,7 +16083,9 @@ var ProcedureService = class extends BaseService {
15869
16083
  const pageSize = filters.pagination || 10;
15870
16084
  let startIndex = 0;
15871
16085
  if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
15872
- const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
16086
+ const idx = procedures.findIndex(
16087
+ (p) => p.id === filters.lastDoc.id
16088
+ );
15873
16089
  if (idx >= 0) startIndex = idx + 1;
15874
16090
  }
15875
16091
  const page = procedures.slice(startIndex, startIndex + pageSize);
@@ -15894,7 +16110,7 @@ var ProcedureService = class extends BaseService {
15894
16110
  * @returns The created procedure
15895
16111
  */
15896
16112
  async createConsultationProcedure(data) {
15897
- var _a;
16113
+ var _a, _b, _c;
15898
16114
  const procedureId = this.generateId();
15899
16115
  const [category, subcategory, technology] = await Promise.all([
15900
16116
  this.categoryService.getById(data.categoryId),
@@ -15910,7 +16126,11 @@ var ProcedureService = class extends BaseService {
15910
16126
  throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
15911
16127
  }
15912
16128
  const clinic = clinicSnapshot.data();
15913
- const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
16129
+ const practitionerRef = doc30(
16130
+ this.db,
16131
+ PRACTITIONERS_COLLECTION,
16132
+ data.practitionerId
16133
+ );
15914
16134
  const practitionerSnapshot = await getDoc32(practitionerRef);
15915
16135
  if (!practitionerSnapshot.exists()) {
15916
16136
  throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
@@ -15918,7 +16138,11 @@ var ProcedureService = class extends BaseService {
15918
16138
  const practitioner = practitionerSnapshot.data();
15919
16139
  let processedPhotos = [];
15920
16140
  if (data.photos && data.photos.length > 0) {
15921
- processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
16141
+ processedPhotos = await this.processMediaArray(
16142
+ data.photos,
16143
+ procedureId,
16144
+ "procedure-photos"
16145
+ );
15922
16146
  }
15923
16147
  const clinicInfo = {
15924
16148
  id: clinicSnapshot.id,
@@ -15944,6 +16168,8 @@ var ProcedureService = class extends BaseService {
15944
16168
  brandName: "Consultation",
15945
16169
  technologyId: data.technologyId,
15946
16170
  technologyName: technology.name,
16171
+ categoryId: technology.categoryId,
16172
+ subcategoryId: technology.subcategoryId,
15947
16173
  isActive: true,
15948
16174
  createdAt: /* @__PURE__ */ new Date(),
15949
16175
  updatedAt: /* @__PURE__ */ new Date()
@@ -15960,7 +16186,9 @@ var ProcedureService = class extends BaseService {
15960
16186
  // Use placeholder product
15961
16187
  blockingConditions: technology.blockingConditions,
15962
16188
  contraindications: technology.contraindications || [],
16189
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
15963
16190
  treatmentBenefits: technology.benefits,
16191
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
15964
16192
  preRequirements: technology.requirements.pre,
15965
16193
  postRequirements: technology.requirements.post,
15966
16194
  certificationRequirement: technology.certificationRequirement,
@@ -15996,11 +16224,11 @@ var ProcedureService = class extends BaseService {
15996
16224
  async getProceduresForMap() {
15997
16225
  const proceduresRef = collection29(this.db, PROCEDURES_COLLECTION);
15998
16226
  const snapshot = await getDocs29(proceduresRef);
15999
- const proceduresForMap = snapshot.docs.map((doc37) => {
16227
+ const proceduresForMap = snapshot.docs.map((doc38) => {
16000
16228
  var _a, _b, _c, _d, _e, _f, _g, _h;
16001
- const data = doc37.data();
16229
+ const data = doc38.data();
16002
16230
  return {
16003
- id: doc37.id,
16231
+ id: doc38.id,
16004
16232
  name: data.name,
16005
16233
  clinicId: (_a = data.clinicInfo) == null ? void 0 : _a.id,
16006
16234
  clinicName: (_b = data.clinicInfo) == null ? void 0 : _b.name,
@@ -16142,7 +16370,7 @@ var ReviewService = class extends BaseService {
16142
16370
  where30("patientId", "==", patientId)
16143
16371
  );
16144
16372
  const snapshot = await getDocs30(q);
16145
- return snapshot.docs.map((doc37) => doc37.data());
16373
+ return snapshot.docs.map((doc38) => doc38.data());
16146
16374
  }
16147
16375
  /**
16148
16376
  * Gets all reviews for a specific clinic
@@ -16155,7 +16383,7 @@ var ReviewService = class extends BaseService {
16155
16383
  where30("clinicReview.clinicId", "==", clinicId)
16156
16384
  );
16157
16385
  const snapshot = await getDocs30(q);
16158
- return snapshot.docs.map((doc37) => doc37.data());
16386
+ return snapshot.docs.map((doc38) => doc38.data());
16159
16387
  }
16160
16388
  /**
16161
16389
  * Gets all reviews for a specific practitioner
@@ -16168,7 +16396,7 @@ var ReviewService = class extends BaseService {
16168
16396
  where30("practitionerReview.practitionerId", "==", practitionerId)
16169
16397
  );
16170
16398
  const snapshot = await getDocs30(q);
16171
- return snapshot.docs.map((doc37) => doc37.data());
16399
+ return snapshot.docs.map((doc38) => doc38.data());
16172
16400
  }
16173
16401
  /**
16174
16402
  * Gets all reviews for a specific procedure
@@ -16181,7 +16409,7 @@ var ReviewService = class extends BaseService {
16181
16409
  where30("procedureReview.procedureId", "==", procedureId)
16182
16410
  );
16183
16411
  const snapshot = await getDocs30(q);
16184
- return snapshot.docs.map((doc37) => doc37.data());
16412
+ return snapshot.docs.map((doc38) => doc38.data());
16185
16413
  }
16186
16414
  /**
16187
16415
  * Gets all reviews for a specific appointment
@@ -16287,7 +16515,11 @@ import {
16287
16515
  getDocs as getDocs31,
16288
16516
  query as query31,
16289
16517
  updateDoc as updateDoc30,
16290
- where as where31
16518
+ where as where31,
16519
+ limit as limit16,
16520
+ orderBy as orderBy18,
16521
+ startAfter as startAfter14,
16522
+ getCountFromServer as getCountFromServer2
16291
16523
  } from "firebase/firestore";
16292
16524
 
16293
16525
  // src/backoffice/types/brand.types.ts
@@ -16308,6 +16540,7 @@ var BrandService = class extends BaseService {
16308
16540
  const now = /* @__PURE__ */ new Date();
16309
16541
  const newBrand = {
16310
16542
  ...brand,
16543
+ name_lowercase: brand.name.toLowerCase(),
16311
16544
  createdAt: now,
16312
16545
  updatedAt: now,
16313
16546
  isActive: true
@@ -16316,15 +16549,69 @@ var BrandService = class extends BaseService {
16316
16549
  return { id: docRef.id, ...newBrand };
16317
16550
  }
16318
16551
  /**
16319
- * 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).
16320
16603
  */
16321
- async getAll() {
16322
- 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
+ );
16323
16610
  const snapshot = await getDocs31(q);
16324
16611
  return snapshot.docs.map(
16325
- (doc37) => ({
16326
- id: doc37.id,
16327
- ...doc37.data()
16612
+ (doc38) => ({
16613
+ id: doc38.id,
16614
+ ...doc38.data()
16328
16615
  })
16329
16616
  );
16330
16617
  }
@@ -16336,6 +16623,9 @@ var BrandService = class extends BaseService {
16336
16623
  ...brand,
16337
16624
  updatedAt: /* @__PURE__ */ new Date()
16338
16625
  };
16626
+ if (brand.name) {
16627
+ updateData.name_lowercase = brand.name.toLowerCase();
16628
+ }
16339
16629
  const docRef = doc32(this.getBrandsRef(), brandId);
16340
16630
  await updateDoc30(docRef, updateData);
16341
16631
  return this.getById(brandId);
@@ -16367,9 +16657,13 @@ import {
16367
16657
  addDoc as addDoc4,
16368
16658
  collection as collection32,
16369
16659
  doc as doc33,
16660
+ getCountFromServer as getCountFromServer3,
16370
16661
  getDoc as getDoc35,
16371
16662
  getDocs as getDocs32,
16663
+ limit as limit17,
16664
+ orderBy as orderBy19,
16372
16665
  query as query32,
16666
+ startAfter as startAfter15,
16373
16667
  updateDoc as updateDoc31,
16374
16668
  where as where32
16375
16669
  } from "firebase/firestore";
@@ -16402,37 +16696,87 @@ var CategoryService = class extends BaseService {
16402
16696
  return { id: docRef.id, ...newCategory };
16403
16697
  }
16404
16698
  /**
16405
- * Vraća sve aktivne kategorije
16406
- * @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
16407
16720
  */
16408
- async getAll() {
16721
+ async getAllForFilter() {
16409
16722
  const q = query32(this.categoriesRef, where32("isActive", "==", true));
16410
16723
  const snapshot = await getDocs32(q);
16411
16724
  return snapshot.docs.map(
16412
- (doc37) => ({
16413
- id: doc37.id,
16414
- ...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()
16415
16750
  })
16416
16751
  );
16752
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
16753
+ return { categories, lastVisible: newLastVisible };
16417
16754
  }
16418
16755
  /**
16419
- * Vraća sve aktivne kategorije za određenu familiju procedura
16756
+ * Vraća sve aktivne kategorije za određenu familiju procedura sa paginacijom
16420
16757
  * @param family - Familija procedura (aesthetics/surgery)
16758
+ * @param options - Pagination options
16421
16759
  * @returns Lista kategorija koje pripadaju traženoj familiji
16422
16760
  */
16423
- async getAllByFamily(family) {
16424
- const q = query32(
16425
- this.categoriesRef,
16761
+ async getAllByFamily(family, options = {}) {
16762
+ const { active = true, limit: queryLimit = 10, lastVisible } = options;
16763
+ const constraints = [
16426
16764
  where32("family", "==", family),
16427
- where32("isActive", "==", true)
16428
- );
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);
16429
16771
  const snapshot = await getDocs32(q);
16430
- return snapshot.docs.map(
16431
- (doc37) => ({
16432
- id: doc37.id,
16433
- ...doc37.data()
16772
+ const categories = snapshot.docs.map(
16773
+ (doc38) => ({
16774
+ id: doc38.id,
16775
+ ...doc38.data()
16434
16776
  })
16435
16777
  );
16778
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
16779
+ return { categories, lastVisible: newLastVisible };
16436
16780
  }
16437
16781
  /**
16438
16782
  * Ažurira postojeću kategoriju
@@ -16456,6 +16800,13 @@ var CategoryService = class extends BaseService {
16456
16800
  async delete(id) {
16457
16801
  await this.update(id, { isActive: false });
16458
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
+ }
16459
16810
  /**
16460
16811
  * Vraća kategoriju po ID-u
16461
16812
  * @param id - ID tražene kategorije
@@ -16476,10 +16827,17 @@ var CategoryService = class extends BaseService {
16476
16827
  import {
16477
16828
  addDoc as addDoc5,
16478
16829
  collection as collection33,
16830
+ collectionGroup as collectionGroup2,
16831
+ deleteDoc as deleteDoc20,
16479
16832
  doc as doc34,
16833
+ getCountFromServer as getCountFromServer4,
16480
16834
  getDoc as getDoc36,
16481
16835
  getDocs as getDocs33,
16836
+ limit as limit18,
16837
+ orderBy as orderBy20,
16482
16838
  query as query33,
16839
+ setDoc as setDoc28,
16840
+ startAfter as startAfter16,
16483
16841
  updateDoc as updateDoc32,
16484
16842
  where as where33
16485
16843
  } from "firebase/firestore";
@@ -16523,20 +16881,110 @@ var SubcategoryService = class extends BaseService {
16523
16881
  return { id: docRef.id, ...newSubcategory };
16524
16882
  }
16525
16883
  /**
16526
- * 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
16527
16903
  * @param categoryId - ID kategorije čije podkategorije tražimo
16528
- * @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
16529
16933
  */
16530
- 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) {
16531
16962
  const q = query33(
16532
16963
  this.getSubcategoriesRef(categoryId),
16533
16964
  where33("isActive", "==", true)
16534
16965
  );
16535
- const snapshot = await getDocs33(q);
16536
- return snapshot.docs.map(
16537
- (doc37) => ({
16538
- id: doc37.id,
16539
- ...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()
16540
16988
  })
16541
16989
  );
16542
16990
  }
@@ -16548,13 +16996,42 @@ var SubcategoryService = class extends BaseService {
16548
16996
  * @returns Ažurirana podkategorija
16549
16997
  */
16550
16998
  async update(categoryId, subcategoryId, subcategory) {
16551
- const updateData = {
16552
- ...subcategory,
16553
- updatedAt: /* @__PURE__ */ new Date()
16554
- };
16555
- const docRef = doc34(this.getSubcategoriesRef(categoryId), subcategoryId);
16556
- await updateDoc32(docRef, updateData);
16557
- 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
+ }
16558
17035
  }
16559
17036
  /**
16560
17037
  * Soft delete podkategorije (postavlja isActive na false)
@@ -16564,6 +17041,14 @@ var SubcategoryService = class extends BaseService {
16564
17041
  async delete(categoryId, subcategoryId) {
16565
17042
  await this.update(categoryId, subcategoryId, { isActive: false });
16566
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
+ }
16567
17052
  /**
16568
17053
  * Vraća podkategoriju po ID-u
16569
17054
  * @param categoryId - ID kategorije kojoj pripada podkategorija
@@ -16588,7 +17073,10 @@ import {
16588
17073
  doc as doc35,
16589
17074
  getDoc as getDoc37,
16590
17075
  getDocs as getDocs34,
17076
+ limit as limit19,
17077
+ orderBy as orderBy21,
16591
17078
  query as query34,
17079
+ startAfter as startAfter17,
16592
17080
  updateDoc as updateDoc33,
16593
17081
  where as where34,
16594
17082
  arrayUnion as arrayUnion9,
@@ -16600,137 +17088,185 @@ var DEFAULT_CERTIFICATION_REQUIREMENT = {
16600
17088
  };
16601
17089
  var TechnologyService = class extends BaseService {
16602
17090
  /**
16603
- * Vraća referencu na Firestore kolekciju tehnologija
17091
+ * Reference to the Firestore collection of technologies.
16604
17092
  */
16605
- getTechnologiesRef() {
17093
+ get technologiesRef() {
16606
17094
  return collection34(this.db, TECHNOLOGIES_COLLECTION);
16607
17095
  }
16608
17096
  /**
16609
- * Kreira novu tehnologiju
16610
- * @param technology - Podaci za novu tehnologiju
16611
- * @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.
16612
17100
  */
16613
17101
  async create(technology) {
16614
17102
  const now = /* @__PURE__ */ new Date();
16615
17103
  const newTechnology = {
16616
- ...technology,
16617
- createdAt: now,
16618
- updatedAt: now,
16619
- isActive: true,
16620
- requirements: technology.requirements || {
16621
- pre: [],
16622
- post: []
16623
- },
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: [] },
16624
17110
  blockingConditions: technology.blockingConditions || [],
16625
17111
  contraindications: technology.contraindications || [],
16626
17112
  benefits: technology.benefits || [],
16627
- 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
16628
17118
  };
16629
- 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);
16630
17123
  return { id: docRef.id, ...newTechnology };
16631
17124
  }
16632
17125
  /**
16633
- * Vraća sve aktivne tehnologije
16634
- * @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.
16635
17129
  */
16636
- async getAll() {
16637
- const q = query34(this.getTechnologiesRef(), where34("isActive", "==", true));
17130
+ async getTechnologyCounts(active = true) {
17131
+ const q = query34(this.technologiesRef, where34("isActive", "==", active));
16638
17132
  const snapshot = await getDocs34(q);
16639
- return snapshot.docs.map(
16640
- (doc37) => ({
16641
- id: doc37.id,
16642
- ...doc37.data()
16643
- })
16644
- );
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;
16645
17139
  }
16646
17140
  /**
16647
- * Vraća sve aktivne tehnologije za određenu familiju
16648
- * @param family - Familija procedura
16649
- * @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.
16650
17144
  */
16651
- async getAllByFamily(family) {
16652
- const q = query34(
16653
- this.getTechnologiesRef(),
16654
- where34("isActive", "==", true),
16655
- where34("family", "==", family)
16656
- );
17145
+ async getTechnologyCountsByCategory(active = true) {
17146
+ const q = query34(this.technologiesRef, where34("isActive", "==", active));
16657
17147
  const snapshot = await getDocs34(q);
16658
- return snapshot.docs.map(
16659
- (doc37) => ({
16660
- id: doc37.id,
16661
- ...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()
16662
17174
  })
16663
17175
  );
17176
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
17177
+ return { technologies, lastVisible: newLastVisible };
16664
17178
  }
16665
17179
  /**
16666
- * Vraća sve aktivne tehnologije za određenu kategoriju
16667
- * @param categoryId - ID kategorije
16668
- * @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.
16669
17184
  */
16670
- async getAllByCategoryId(categoryId) {
16671
- const q = query34(
16672
- this.getTechnologiesRef(),
16673
- where34("isActive", "==", true),
16674
- where34("categoryId", "==", categoryId)
16675
- );
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);
16676
17195
  const snapshot = await getDocs34(q);
16677
- return snapshot.docs.map(
16678
- (doc37) => ({
16679
- id: doc37.id,
16680
- ...doc37.data()
17196
+ const technologies = snapshot.docs.map(
17197
+ (doc38) => ({
17198
+ id: doc38.id,
17199
+ ...doc38.data()
16681
17200
  })
16682
17201
  );
17202
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
17203
+ return { technologies, lastVisible: newLastVisible };
16683
17204
  }
16684
17205
  /**
16685
- * Vraća sve aktivne tehnologije za određenu podkategoriju
16686
- * @param subcategoryId - ID podkategorije
16687
- * @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.
16688
17210
  */
16689
- async getAllBySubcategoryId(subcategoryId) {
16690
- const q = query34(
16691
- this.getTechnologiesRef(),
16692
- where34("isActive", "==", true),
16693
- where34("subcategoryId", "==", subcategoryId)
16694
- );
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);
16695
17221
  const snapshot = await getDocs34(q);
16696
- return snapshot.docs.map(
16697
- (doc37) => ({
16698
- id: doc37.id,
16699
- ...doc37.data()
17222
+ const technologies = snapshot.docs.map(
17223
+ (doc38) => ({
17224
+ id: doc38.id,
17225
+ ...doc38.data()
16700
17226
  })
16701
17227
  );
17228
+ const newLastVisible = snapshot.docs[snapshot.docs.length - 1];
17229
+ return { technologies, lastVisible: newLastVisible };
16702
17230
  }
16703
17231
  /**
16704
- * Ažurira postojeću tehnologiju
16705
- * @param technologyId - ID tehnologije
16706
- * @param technology - Novi podaci za tehnologiju
16707
- * @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.
16708
17236
  */
16709
- async update(technologyId, technology) {
16710
- const updateData = {
16711
- ...technology,
16712
- updatedAt: /* @__PURE__ */ new Date()
16713
- };
16714
- 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);
16715
17246
  await updateDoc33(docRef, updateData);
16716
- return this.getById(technologyId);
17247
+ return this.getById(id);
16717
17248
  }
16718
17249
  /**
16719
- * Soft delete tehnologije (postavlja isActive na false)
16720
- * @param technologyId - ID tehnologije koja se briše
17250
+ * Soft deletes a technology.
17251
+ * @param id - The ID of the technology to delete.
16721
17252
  */
16722
- async delete(technologyId) {
16723
- await this.update(technologyId, {
16724
- isActive: false
16725
- });
17253
+ async delete(id) {
17254
+ await this.update(id, { isActive: false });
16726
17255
  }
16727
17256
  /**
16728
- * Vraća tehnologiju po ID-u
16729
- * @param technologyId - ID tražene tehnologije
16730
- * @returns Tehnologija ili null ako ne postoji
17257
+ * Reactivates a technology.
17258
+ * @param id - The ID of the technology to reactivate.
16731
17259
  */
16732
- async getById(technologyId) {
16733
- 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);
16734
17270
  const docSnap = await getDoc37(docRef);
16735
17271
  if (!docSnap.exists()) return null;
16736
17272
  return {
@@ -16745,7 +17281,7 @@ var TechnologyService = class extends BaseService {
16745
17281
  * @returns Ažurirana tehnologija sa novim zahtevom
16746
17282
  */
16747
17283
  async addRequirement(technologyId, requirement) {
16748
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17284
+ const docRef = doc35(this.technologiesRef, technologyId);
16749
17285
  const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
16750
17286
  await updateDoc33(docRef, {
16751
17287
  [requirementType]: arrayUnion9(requirement),
@@ -16760,7 +17296,7 @@ var TechnologyService = class extends BaseService {
16760
17296
  * @returns Ažurirana tehnologija bez uklonjenog zahteva
16761
17297
  */
16762
17298
  async removeRequirement(technologyId, requirement) {
16763
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17299
+ const docRef = doc35(this.technologiesRef, technologyId);
16764
17300
  const requirementType = requirement.type === "pre" ? "requirements.pre" : "requirements.post";
16765
17301
  await updateDoc33(docRef, {
16766
17302
  [requirementType]: arrayRemove8(requirement),
@@ -16800,7 +17336,7 @@ var TechnologyService = class extends BaseService {
16800
17336
  * @returns Ažurirana tehnologija
16801
17337
  */
16802
17338
  async addBlockingCondition(technologyId, condition) {
16803
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17339
+ const docRef = doc35(this.technologiesRef, technologyId);
16804
17340
  await updateDoc33(docRef, {
16805
17341
  blockingConditions: arrayUnion9(condition),
16806
17342
  updatedAt: /* @__PURE__ */ new Date()
@@ -16814,7 +17350,7 @@ var TechnologyService = class extends BaseService {
16814
17350
  * @returns Ažurirana tehnologija
16815
17351
  */
16816
17352
  async removeBlockingCondition(technologyId, condition) {
16817
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17353
+ const docRef = doc35(this.technologiesRef, technologyId);
16818
17354
  await updateDoc33(docRef, {
16819
17355
  blockingConditions: arrayRemove8(condition),
16820
17356
  updatedAt: /* @__PURE__ */ new Date()
@@ -16828,9 +17364,17 @@ var TechnologyService = class extends BaseService {
16828
17364
  * @returns Ažurirana tehnologija
16829
17365
  */
16830
17366
  async addContraindication(technologyId, contraindication) {
16831
- 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
+ }
16832
17376
  await updateDoc33(docRef, {
16833
- contraindications: arrayUnion9(contraindication),
17377
+ contraindications: [...existingContraindications, contraindication],
16834
17378
  updatedAt: /* @__PURE__ */ new Date()
16835
17379
  });
16836
17380
  return this.getById(technologyId);
@@ -16842,9 +17386,45 @@ var TechnologyService = class extends BaseService {
16842
17386
  * @returns Ažurirana tehnologija
16843
17387
  */
16844
17388
  async removeContraindication(technologyId, contraindication) {
16845
- 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;
16846
17426
  await updateDoc33(docRef, {
16847
- contraindications: arrayRemove8(contraindication),
17427
+ contraindications: updatedContraindications,
16848
17428
  updatedAt: /* @__PURE__ */ new Date()
16849
17429
  });
16850
17430
  return this.getById(technologyId);
@@ -16856,9 +17436,17 @@ var TechnologyService = class extends BaseService {
16856
17436
  * @returns Ažurirana tehnologija
16857
17437
  */
16858
17438
  async addBenefit(technologyId, benefit) {
16859
- 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
+ }
16860
17448
  await updateDoc33(docRef, {
16861
- benefits: arrayUnion9(benefit),
17449
+ benefits: [...existingBenefits, benefit],
16862
17450
  updatedAt: /* @__PURE__ */ new Date()
16863
17451
  });
16864
17452
  return this.getById(technologyId);
@@ -16870,9 +17458,45 @@ var TechnologyService = class extends BaseService {
16870
17458
  * @returns Ažurirana tehnologija
16871
17459
  */
16872
17460
  async removeBenefit(technologyId, benefit) {
16873
- 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;
16874
17498
  await updateDoc33(docRef, {
16875
- benefits: arrayRemove8(benefit),
17499
+ benefits: updatedBenefits,
16876
17500
  updatedAt: /* @__PURE__ */ new Date()
16877
17501
  });
16878
17502
  return this.getById(technologyId);
@@ -16911,7 +17535,7 @@ var TechnologyService = class extends BaseService {
16911
17535
  * @returns Ažurirana tehnologija
16912
17536
  */
16913
17537
  async updateCertificationRequirement(technologyId, certificationRequirement) {
16914
- const docRef = doc35(this.getTechnologiesRef(), technologyId);
17538
+ const docRef = doc35(this.technologiesRef, technologyId);
16915
17539
  await updateDoc33(docRef, {
16916
17540
  certificationRequirement,
16917
17541
  updatedAt: /* @__PURE__ */ new Date()
@@ -16989,7 +17613,7 @@ var TechnologyService = class extends BaseService {
16989
17613
  */
16990
17614
  async getAllowedTechnologies(practitioner) {
16991
17615
  const allTechnologies = await this.getAll();
16992
- const allowedTechnologies = allTechnologies.filter(
17616
+ const allowedTechnologies = allTechnologies.technologies.filter(
16993
17617
  (technology) => this.validateCertification(
16994
17618
  technology.certificationRequirement,
16995
17619
  practitioner.certification
@@ -17009,18 +17633,61 @@ var TechnologyService = class extends BaseService {
17009
17633
  subcategories
17010
17634
  };
17011
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
+ }
17012
17674
  };
17013
17675
 
17014
17676
  // src/backoffice/services/product.service.ts
17015
17677
  import {
17016
17678
  addDoc as addDoc7,
17017
17679
  collection as collection35,
17680
+ collectionGroup as collectionGroup3,
17018
17681
  doc as doc36,
17019
17682
  getDoc as getDoc38,
17020
17683
  getDocs as getDocs35,
17021
17684
  query as query35,
17022
17685
  updateDoc as updateDoc34,
17023
- where as where35
17686
+ where as where35,
17687
+ limit as limit20,
17688
+ orderBy as orderBy22,
17689
+ startAfter as startAfter18,
17690
+ getCountFromServer as getCountFromServer6
17024
17691
  } from "firebase/firestore";
17025
17692
 
17026
17693
  // src/backoffice/types/product.types.ts
@@ -17061,20 +17728,102 @@ var ProductService = class extends BaseService {
17061
17728
  return { id: productRef.id, ...newProduct };
17062
17729
  }
17063
17730
  /**
17064
- * 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.
17065
17733
  */
17066
- 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));
17067
17759
  const q = query35(
17068
- this.getProductsRef(technologyId),
17069
- where35("isActive", "==", true)
17760
+ collectionGroup3(this.db, PRODUCTS_COLLECTION),
17761
+ ...constraints
17070
17762
  );
17071
17763
  const snapshot = await getDocs35(q);
17072
- return snapshot.docs.map(
17073
- (doc37) => ({
17074
- id: doc37.id,
17075
- ...doc37.data()
17764
+ const products = snapshot.docs.map(
17765
+ (doc38) => ({
17766
+ id: doc38.id,
17767
+ ...doc38.data()
17076
17768
  })
17077
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;
17078
17827
  }
17079
17828
  /**
17080
17829
  * Gets all products for a brand by filtering through all technologies
@@ -17092,9 +17841,9 @@ var ProductService = class extends BaseService {
17092
17841
  const snapshot = await getDocs35(q);
17093
17842
  products.push(
17094
17843
  ...snapshot.docs.map(
17095
- (doc37) => ({
17096
- id: doc37.id,
17097
- ...doc37.data()
17844
+ (doc38) => ({
17845
+ id: doc38.id,
17846
+ ...doc38.data()
17098
17847
  })
17099
17848
  )
17100
17849
  );
@@ -17135,6 +17884,262 @@ var ProductService = class extends BaseService {
17135
17884
  }
17136
17885
  };
17137
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
+
17138
18143
  // src/backoffice/types/static/treatment-benefit.types.ts
17139
18144
  var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
17140
18145
  TreatmentBenefit2["WRINKLE_REDUCTION"] = "wrinkle_reduction";
@@ -17193,6 +18198,7 @@ export {
17193
18198
  ClinicPhotoTag,
17194
18199
  ClinicService,
17195
18200
  ClinicTag,
18201
+ ConstantsService,
17196
18202
  Contraindication,
17197
18203
  CosmeticAllergySubtype,
17198
18204
  Currency,