@blackcode_sa/metaestetics-api 1.10.0 → 1.11.1

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 (43) hide show
  1. package/dist/admin/index.d.mts +337 -319
  2. package/dist/admin/index.d.ts +337 -319
  3. package/dist/admin/index.js +98 -79
  4. package/dist/admin/index.mjs +98 -79
  5. package/dist/backoffice/index.d.mts +284 -67
  6. package/dist/backoffice/index.d.ts +284 -67
  7. package/dist/backoffice/index.js +114 -6
  8. package/dist/backoffice/index.mjs +112 -6
  9. package/dist/index.d.mts +3145 -3065
  10. package/dist/index.d.ts +3145 -3065
  11. package/dist/index.js +460 -141
  12. package/dist/index.mjs +463 -143
  13. package/package.json +3 -1
  14. package/src/admin/booking/booking.admin.ts +2 -0
  15. package/src/admin/booking/booking.calculator.ts +121 -117
  16. package/src/admin/booking/booking.types.ts +3 -0
  17. package/src/backoffice/expo-safe/index.ts +2 -0
  18. package/src/backoffice/services/README.md +40 -0
  19. package/src/backoffice/services/constants.service.ts +268 -0
  20. package/src/backoffice/services/technology.service.ts +122 -10
  21. package/src/backoffice/types/admin-constants.types.ts +69 -0
  22. package/src/backoffice/types/index.ts +1 -0
  23. package/src/backoffice/types/product.types.ts +3 -1
  24. package/src/backoffice/types/technology.types.ts +4 -4
  25. package/src/backoffice/validations/schemas.ts +35 -9
  26. package/src/services/appointment/appointment.service.ts +0 -5
  27. package/src/services/appointment/utils/appointment.utils.ts +124 -113
  28. package/src/services/clinic/clinic.service.ts +163 -82
  29. package/src/services/procedure/procedure.service.ts +435 -234
  30. package/src/types/appointment/index.ts +9 -3
  31. package/src/types/clinic/index.ts +3 -6
  32. package/src/types/patient/medical-info.types.ts +3 -3
  33. package/src/types/procedure/index.ts +20 -17
  34. package/src/validations/appointment.schema.ts +2 -0
  35. package/src/validations/clinic.schema.ts +3 -6
  36. package/src/validations/patient/medical-info.schema.ts +7 -2
  37. package/src/validations/procedure.schema.ts +8 -10
  38. package/src/backoffice/services/__tests__/brand.service.test.ts +0 -196
  39. package/src/backoffice/services/__tests__/category.service.test.ts +0 -201
  40. package/src/backoffice/services/__tests__/product.service.test.ts +0 -358
  41. package/src/backoffice/services/__tests__/requirement.service.test.ts +0 -226
  42. package/src/backoffice/services/__tests__/subcategory.service.test.ts +0 -181
  43. package/src/backoffice/services/__tests__/technology.service.test.ts +0 -1097
package/dist/index.js CHANGED
@@ -181,13 +181,13 @@ var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
181
181
  AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
182
182
  return AppointmentStatus2;
183
183
  })(AppointmentStatus || {});
184
- var PaymentStatus = /* @__PURE__ */ ((PaymentStatus3) => {
185
- PaymentStatus3["UNPAID"] = "unpaid";
186
- PaymentStatus3["PAID"] = "paid";
187
- PaymentStatus3["PARTIALLY_PAID"] = "partially_paid";
188
- PaymentStatus3["REFUNDED"] = "refunded";
189
- PaymentStatus3["NOT_APPLICABLE"] = "not_applicable";
190
- return PaymentStatus3;
184
+ var PaymentStatus = /* @__PURE__ */ ((PaymentStatus4) => {
185
+ PaymentStatus4["UNPAID"] = "unpaid";
186
+ PaymentStatus4["PAID"] = "paid";
187
+ PaymentStatus4["PARTIALLY_PAID"] = "partially_paid";
188
+ PaymentStatus4["REFUNDED"] = "refunded";
189
+ PaymentStatus4["NOT_APPLICABLE"] = "not_applicable";
190
+ return PaymentStatus4;
191
191
  })(PaymentStatus || {});
192
192
  var MediaType = /* @__PURE__ */ ((MediaType2) => {
193
193
  MediaType2["BEFORE_PHOTO"] = "before_photo";
@@ -583,7 +583,8 @@ var createAppointmentSchema = import_zod3.z.object({
583
583
  currency: import_zod3.z.string().min(1, "Currency is required"),
584
584
  patientNotes: import_zod3.z.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
585
585
  initialStatus: appointmentStatusSchema,
586
- initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
586
+ initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */),
587
+ clinic_tz: import_zod3.z.string().min(1, "Timezone is required")
587
588
  }).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
588
589
  message: "Appointment end time must be after start time",
589
590
  path: ["appointmentEndTime"]
@@ -617,6 +618,7 @@ var updateAppointmentSchema = import_zod3.z.object({
617
618
  cost: import_zod3.z.number().min(0).optional(),
618
619
  clinicBranchId: import_zod3.z.string().min(MIN_STRING_LENGTH).optional(),
619
620
  practitionerId: import_zod3.z.string().min(MIN_STRING_LENGTH).optional(),
621
+ clinic_tz: import_zod3.z.string().min(MIN_STRING_LENGTH).optional(),
620
622
  linkedForms: import_zod3.z.union([import_zod3.z.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), import_zod3.z.any()]).optional(),
621
623
  media: import_zod3.z.union([
622
624
  import_zod3.z.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
@@ -934,44 +936,48 @@ async function updateAppointmentUtil(db, appointmentId, data) {
934
936
  const validPreReqIds = currentAppointment.preProcedureRequirements.map(
935
937
  (req) => req.id
936
938
  );
937
- const invalidPreReqIds = data.completedPreRequirements.filter(
938
- (id) => !validPreReqIds.includes(id)
939
- );
940
- if (invalidPreReqIds.length > 0) {
941
- throw new Error(
942
- `Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
939
+ if (Array.isArray(data.completedPreRequirements)) {
940
+ const invalidPreReqIds = data.completedPreRequirements.filter(
941
+ (id) => !validPreReqIds.includes(id)
943
942
  );
943
+ if (invalidPreReqIds.length > 0) {
944
+ throw new Error(
945
+ `Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
946
+ );
947
+ }
948
+ completedPreRequirements = [
949
+ .../* @__PURE__ */ new Set([
950
+ ...completedPreRequirements,
951
+ ...data.completedPreRequirements
952
+ ])
953
+ ];
944
954
  }
945
- completedPreRequirements = [
946
- .../* @__PURE__ */ new Set([
947
- ...completedPreRequirements,
948
- ...data.completedPreRequirements
949
- ])
950
- ];
951
955
  }
952
956
  if (data.completedPostRequirements) {
953
957
  const validPostReqIds = currentAppointment.postProcedureRequirements.map(
954
958
  (req) => req.id
955
959
  );
956
- const invalidPostReqIds = data.completedPostRequirements.filter(
957
- (id) => !validPostReqIds.includes(id)
958
- );
959
- if (invalidPostReqIds.length > 0) {
960
- throw new Error(
961
- `Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
960
+ if (Array.isArray(data.completedPostRequirements)) {
961
+ const invalidPostReqIds = data.completedPostRequirements.filter(
962
+ (id) => !validPostReqIds.includes(id)
962
963
  );
964
+ if (invalidPostReqIds.length > 0) {
965
+ throw new Error(
966
+ `Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
967
+ );
968
+ }
969
+ completedPostRequirements = [
970
+ .../* @__PURE__ */ new Set([
971
+ ...completedPostRequirements,
972
+ ...data.completedPostRequirements
973
+ ])
974
+ ];
963
975
  }
964
- completedPostRequirements = [
965
- .../* @__PURE__ */ new Set([
966
- ...completedPostRequirements,
967
- ...data.completedPostRequirements
968
- ])
969
- ];
970
976
  }
971
977
  const updateData = {
972
978
  ...data,
973
- completedPreRequirements,
974
- completedPostRequirements,
979
+ completedPreRequirements: Array.isArray(data.completedPreRequirements) ? completedPreRequirements : data.completedPreRequirements,
980
+ completedPostRequirements: Array.isArray(data.completedPostRequirements) ? completedPostRequirements : data.completedPostRequirements,
975
981
  updatedAt: (0, import_firestore.serverTimestamp)()
976
982
  };
977
983
  Object.keys(updateData).forEach((key) => {
@@ -1021,7 +1027,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
1021
1027
  case "canceled_clinic" /* CANCELED_CLINIC */:
1022
1028
  calendarStatus = "canceled";
1023
1029
  break;
1024
- case AppointmentStatus.RESCHEDULED:
1030
+ case "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */:
1025
1031
  calendarStatus = "rescheduled";
1026
1032
  break;
1027
1033
  case "completed" /* COMPLETED */:
@@ -2837,23 +2843,6 @@ var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
2837
2843
  return BlockingCondition2;
2838
2844
  })(BlockingCondition || {});
2839
2845
 
2840
- // src/backoffice/types/static/contraindication.types.ts
2841
- var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
2842
- Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
2843
- Contraindication2["RECENT_TANNING"] = "recent_tanning";
2844
- Contraindication2["RECENT_BOTOX"] = "recent_botox";
2845
- Contraindication2["RECENT_FILLERS"] = "recent_fillers";
2846
- Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
2847
- Contraindication2["MEDICATIONS"] = "medications";
2848
- Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
2849
- Contraindication2["RECENT_LASER"] = "recent_laser";
2850
- Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
2851
- Contraindication2["OPEN_WOUNDS"] = "open_wounds";
2852
- Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
2853
- Contraindication2["COLD_SORES"] = "cold_sores";
2854
- return Contraindication2;
2855
- })(Contraindication || {});
2856
-
2857
2846
  // src/validations/common.schema.ts
2858
2847
  var import_zod5 = require("zod");
2859
2848
  var import_firestore6 = require("firebase/firestore");
@@ -2908,8 +2897,13 @@ var blockingConditionSchema = import_zod6.z.object({
2908
2897
  notes: import_zod6.z.string().optional().nullable(),
2909
2898
  isActive: import_zod6.z.boolean()
2910
2899
  });
2900
+ var contraindicationDynamicSchema = import_zod6.z.object({
2901
+ id: import_zod6.z.string(),
2902
+ name: import_zod6.z.string(),
2903
+ description: import_zod6.z.string().optional()
2904
+ });
2911
2905
  var contraindicationSchema = import_zod6.z.object({
2912
- condition: import_zod6.z.nativeEnum(Contraindication),
2906
+ condition: contraindicationDynamicSchema,
2913
2907
  lastOccurrence: timestampSchema,
2914
2908
  frequency: import_zod6.z.enum(["rare", "occasional", "frequent"]),
2915
2909
  notes: import_zod6.z.string().optional().nullable(),
@@ -3453,7 +3447,8 @@ var clinicLocationSchema = import_zod10.z.object({
3453
3447
  postalCode: import_zod10.z.string(),
3454
3448
  latitude: import_zod10.z.number().min(-90).max(90),
3455
3449
  longitude: import_zod10.z.number().min(-180).max(180),
3456
- geohash: import_zod10.z.string().nullable().optional()
3450
+ geohash: import_zod10.z.string().nullable().optional(),
3451
+ tz: import_zod10.z.string().nullable().optional()
3457
3452
  });
3458
3453
  var workingHoursTimeSchema = import_zod10.z.object({
3459
3454
  open: import_zod10.z.string(),
@@ -3607,6 +3602,7 @@ var createClinicGroupSchema = import_zod10.z.object({
3607
3602
  calendarSyncEnabled: import_zod10.z.boolean().optional(),
3608
3603
  autoConfirmAppointments: import_zod10.z.boolean().optional(),
3609
3604
  businessIdentificationNumber: import_zod10.z.string().optional().nullable(),
3605
+ tz: import_zod10.z.string().nullable().optional(),
3610
3606
  onboarding: import_zod10.z.object({
3611
3607
  completed: import_zod10.z.boolean().optional().default(false),
3612
3608
  step: import_zod10.z.number().optional().default(1)
@@ -8271,6 +8267,7 @@ var ClinicGroupService = class extends BaseService {
8271
8267
 
8272
8268
  // src/services/clinic/clinic.service.ts
8273
8269
  var import_firestore27 = require("firebase/firestore");
8270
+ var import_functions2 = require("firebase/functions");
8274
8271
  var import_geofire_common7 = require("geofire-common");
8275
8272
  var import_zod20 = require("zod");
8276
8273
 
@@ -9023,6 +9020,27 @@ var ClinicService = class extends BaseService {
9023
9020
  this.clinicAdminService = clinicAdminService;
9024
9021
  this.clinicGroupService = clinicGroupService;
9025
9022
  this.mediaService = mediaService;
9023
+ this.functions = (0, import_functions2.getFunctions)(app);
9024
+ }
9025
+ /**
9026
+ * Get timezone from coordinates using the callable function
9027
+ * @param lat Latitude
9028
+ * @param lng Longitude
9029
+ * @returns IANA timezone string
9030
+ */
9031
+ async getTimezone(lat, lng) {
9032
+ try {
9033
+ const getTimezoneFromCoordinates = (0, import_functions2.httpsCallable)(
9034
+ this.functions,
9035
+ "getTimezoneFromCoordinates"
9036
+ );
9037
+ const result = await getTimezoneFromCoordinates({ lat, lng });
9038
+ const data = result.data;
9039
+ return data.timezone;
9040
+ } catch (error) {
9041
+ console.error("Error getting timezone:", error);
9042
+ return null;
9043
+ }
9026
9044
  }
9027
9045
  /**
9028
9046
  * Process media resource (string URL or File object)
@@ -9037,7 +9055,9 @@ var ClinicService = class extends BaseService {
9037
9055
  return media;
9038
9056
  }
9039
9057
  if (media instanceof File || media instanceof Blob) {
9040
- console.log(`[ClinicService] Uploading ${collectionName} media for ${ownerId}`);
9058
+ console.log(
9059
+ `[ClinicService] Uploading ${collectionName} media for ${ownerId}`
9060
+ );
9041
9061
  const metadata = await this.mediaService.uploadMedia(
9042
9062
  media,
9043
9063
  ownerId,
@@ -9059,7 +9079,11 @@ var ClinicService = class extends BaseService {
9059
9079
  if (!mediaArray || mediaArray.length === 0) return [];
9060
9080
  const result = [];
9061
9081
  for (const media of mediaArray) {
9062
- const processedUrl = await this.processMedia(media, ownerId, collectionName);
9082
+ const processedUrl = await this.processMedia(
9083
+ media,
9084
+ ownerId,
9085
+ collectionName
9086
+ );
9063
9087
  if (processedUrl) {
9064
9088
  result.push(processedUrl);
9065
9089
  }
@@ -9077,7 +9101,11 @@ var ClinicService = class extends BaseService {
9077
9101
  if (!photosWithTags || photosWithTags.length === 0) return [];
9078
9102
  const result = [];
9079
9103
  for (const item of photosWithTags) {
9080
- const processedUrl = await this.processMedia(item.url, ownerId, collectionName);
9104
+ const processedUrl = await this.processMedia(
9105
+ item.url,
9106
+ ownerId,
9107
+ collectionName
9108
+ );
9081
9109
  if (processedUrl) {
9082
9110
  result.push({
9083
9111
  url: processedUrl,
@@ -9095,11 +9123,19 @@ var ClinicService = class extends BaseService {
9095
9123
  try {
9096
9124
  const clinicId = this.generateId();
9097
9125
  const validatedData = createClinicSchema.parse(data);
9098
- const group = await this.clinicGroupService.getClinicGroup(validatedData.clinicGroupId);
9126
+ const group = await this.clinicGroupService.getClinicGroup(
9127
+ validatedData.clinicGroupId
9128
+ );
9099
9129
  if (!group) {
9100
- throw new Error(`Clinic group ${validatedData.clinicGroupId} not found`);
9130
+ throw new Error(
9131
+ `Clinic group ${validatedData.clinicGroupId} not found`
9132
+ );
9101
9133
  }
9102
- const logoUrl = await this.processMedia(validatedData.logo, clinicId, "clinic-logos");
9134
+ const logoUrl = await this.processMedia(
9135
+ validatedData.logo,
9136
+ clinicId,
9137
+ "clinic-logos"
9138
+ );
9103
9139
  const coverPhotoUrl = await this.processMedia(
9104
9140
  validatedData.coverPhoto,
9105
9141
  clinicId,
@@ -9117,6 +9153,7 @@ var ClinicService = class extends BaseService {
9117
9153
  );
9118
9154
  const location = validatedData.location;
9119
9155
  const hash = (0, import_geofire_common7.geohashForLocation)([location.latitude, location.longitude]);
9156
+ const tz = await this.getTimezone(location.latitude, location.longitude);
9120
9157
  const defaultReviewInfo = {
9121
9158
  totalReviews: 0,
9122
9159
  averageRating: 0,
@@ -9134,7 +9171,7 @@ var ClinicService = class extends BaseService {
9134
9171
  nameLower: validatedData.name.toLowerCase(),
9135
9172
  // Add this line
9136
9173
  description: validatedData.description,
9137
- location: { ...location, geohash: hash },
9174
+ location: { ...location, geohash: hash, tz },
9138
9175
  contactInfo: validatedData.contactInfo,
9139
9176
  workingHours: validatedData.workingHours,
9140
9177
  tags: validatedData.tags,
@@ -9189,7 +9226,11 @@ var ClinicService = class extends BaseService {
9189
9226
  const validatedData = updateClinicSchema.parse(data);
9190
9227
  const updatePayload = {};
9191
9228
  if (validatedData.logo !== void 0) {
9192
- updatePayload.logo = await this.processMedia(validatedData.logo, clinicId, "clinic-logos");
9229
+ updatePayload.logo = await this.processMedia(
9230
+ validatedData.logo,
9231
+ clinicId,
9232
+ "clinic-logos"
9233
+ );
9193
9234
  }
9194
9235
  if (validatedData.coverPhoto !== void 0) {
9195
9236
  updatePayload.coverPhoto = await this.processMedia(
@@ -9234,9 +9275,11 @@ var ClinicService = class extends BaseService {
9234
9275
  }
9235
9276
  if (validatedData.location) {
9236
9277
  const loc = validatedData.location;
9278
+ const tz = await this.getTimezone(loc.latitude, loc.longitude);
9237
9279
  updatePayload.location = {
9238
9280
  ...loc,
9239
- geohash: (0, import_geofire_common7.geohashForLocation)([loc.latitude, loc.longitude])
9281
+ geohash: (0, import_geofire_common7.geohashForLocation)([loc.latitude, loc.longitude]),
9282
+ tz
9240
9283
  };
9241
9284
  }
9242
9285
  updatePayload.updatedAt = (0, import_firestore27.serverTimestamp)();
@@ -9289,10 +9332,22 @@ var ClinicService = class extends BaseService {
9289
9332
  * Pretražuje klinike u određenom radijusu
9290
9333
  */
9291
9334
  async findClinicsInRadius(center, radiusInKm, filters) {
9292
- return findClinicsInRadius(this.db, center, radiusInKm, filters);
9335
+ return findClinicsInRadius(
9336
+ this.db,
9337
+ center,
9338
+ radiusInKm,
9339
+ filters
9340
+ );
9293
9341
  }
9294
9342
  async addTags(clinicId, adminId, newTags) {
9295
- return addTags(this.db, clinicId, adminId, newTags, this.clinicAdminService, this.app);
9343
+ return addTags(
9344
+ this.db,
9345
+ clinicId,
9346
+ adminId,
9347
+ newTags,
9348
+ this.clinicAdminService,
9349
+ this.app
9350
+ );
9296
9351
  }
9297
9352
  async removeTags(clinicId, adminId, tagsToRemove) {
9298
9353
  return removeTags(
@@ -9330,7 +9385,9 @@ var ClinicService = class extends BaseService {
9330
9385
  clinicGroupId,
9331
9386
  adminId
9332
9387
  });
9333
- const clinicGroup = await this.clinicGroupService.getClinicGroup(clinicGroupId);
9388
+ const clinicGroup = await this.clinicGroupService.getClinicGroup(
9389
+ clinicGroupId
9390
+ );
9334
9391
  if (!clinicGroup) {
9335
9392
  console.error("[CLINIC_SERVICE] Clinic group not found", {
9336
9393
  clinicGroupId
@@ -9376,7 +9433,13 @@ var ClinicService = class extends BaseService {
9376
9433
  return getAllClinics(this.db, pagination, lastDoc);
9377
9434
  }
9378
9435
  async getAllClinicsInRange(center, rangeInKm, pagination, lastDoc) {
9379
- return getAllClinicsInRange(this.db, center, rangeInKm, pagination, lastDoc);
9436
+ return getAllClinicsInRange(
9437
+ this.db,
9438
+ center,
9439
+ rangeInKm,
9440
+ pagination,
9441
+ lastDoc
9442
+ );
9380
9443
  }
9381
9444
  /**
9382
9445
  * Get clinics based on multiple filtering criteria
@@ -10560,7 +10623,7 @@ async function updatePractitionerCalendarEventUtil(db, practitionerId, eventId,
10560
10623
  }
10561
10624
 
10562
10625
  // src/services/calendar/utils/appointment.utils.ts
10563
- async function createAppointmentUtil2(db, clinicId, practitionerId, patientId, eventData, generateId2) {
10626
+ async function createAppointmentUtil(db, clinicId, practitionerId, patientId, eventData, generateId2) {
10564
10627
  const eventId = generateId2();
10565
10628
  const autoConfirm = await checkAutoConfirmAppointmentsUtil(db, clinicId);
10566
10629
  const initialStatus = autoConfirm ? "confirmed" /* CONFIRMED */ : "pending" /* PENDING */;
@@ -11878,7 +11941,7 @@ var CalendarServiceV2 = class extends BaseService {
11878
11941
  syncStatus: "internal" /* INTERNAL */,
11879
11942
  eventType: "appointment" /* APPOINTMENT */
11880
11943
  };
11881
- const appointment = await createAppointmentUtil2(
11944
+ const appointment = await createAppointmentUtil(
11882
11945
  this.db,
11883
11946
  params.clinicId,
11884
11947
  params.doctorId,
@@ -14589,7 +14652,8 @@ var import_firestore45 = require("firebase/firestore");
14589
14652
  var import_zod24 = require("zod");
14590
14653
  var createProcedureSchema = import_zod24.z.object({
14591
14654
  name: import_zod24.z.string().min(1).max(200),
14592
- nameLower: import_zod24.z.string().min(1).max(200),
14655
+ // Optional: service will derive from name if not provided by client
14656
+ nameLower: import_zod24.z.string().min(1).max(200).optional(),
14593
14657
  description: import_zod24.z.string().min(1).max(2e3),
14594
14658
  family: import_zod24.z.nativeEnum(ProcedureFamily),
14595
14659
  categoryId: import_zod24.z.string().min(1),
@@ -14682,7 +14746,9 @@ var ProcedureService = class extends BaseService {
14682
14746
  return media;
14683
14747
  }
14684
14748
  if (media instanceof File || media instanceof Blob) {
14685
- console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
14749
+ console.log(
14750
+ `[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
14751
+ );
14686
14752
  const metadata = await this.mediaService.uploadMedia(
14687
14753
  media,
14688
14754
  ownerId,
@@ -14704,7 +14770,11 @@ var ProcedureService = class extends BaseService {
14704
14770
  if (!mediaArray || mediaArray.length === 0) return [];
14705
14771
  const result = [];
14706
14772
  for (const media of mediaArray) {
14707
- const processedUrl = await this.processMedia(media, ownerId, collectionName);
14773
+ const processedUrl = await this.processMedia(
14774
+ media,
14775
+ ownerId,
14776
+ collectionName
14777
+ );
14708
14778
  if (processedUrl) {
14709
14779
  result.push(processedUrl);
14710
14780
  }
@@ -14717,28 +14787,46 @@ var ProcedureService = class extends BaseService {
14717
14787
  * @returns The created procedure
14718
14788
  */
14719
14789
  async createProcedure(data) {
14720
- var _a;
14790
+ var _a, _b, _c;
14721
14791
  const validatedData = createProcedureSchema.parse(data);
14722
14792
  const procedureId = this.generateId();
14723
14793
  const [category, subcategory, technology, product] = await Promise.all([
14724
14794
  this.categoryService.getById(validatedData.categoryId),
14725
- this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
14795
+ this.subcategoryService.getById(
14796
+ validatedData.categoryId,
14797
+ validatedData.subcategoryId
14798
+ ),
14726
14799
  this.technologyService.getById(validatedData.technologyId),
14727
- this.productService.getById(validatedData.technologyId, validatedData.productId)
14800
+ this.productService.getById(
14801
+ validatedData.technologyId,
14802
+ validatedData.productId
14803
+ )
14728
14804
  ]);
14729
14805
  if (!category || !subcategory || !technology || !product) {
14730
14806
  throw new Error("One or more required base entities not found");
14731
14807
  }
14732
- const clinicRef = (0, import_firestore45.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
14808
+ const clinicRef = (0, import_firestore45.doc)(
14809
+ this.db,
14810
+ CLINICS_COLLECTION,
14811
+ validatedData.clinicBranchId
14812
+ );
14733
14813
  const clinicSnapshot = await (0, import_firestore45.getDoc)(clinicRef);
14734
14814
  if (!clinicSnapshot.exists()) {
14735
- throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
14815
+ throw new Error(
14816
+ `Clinic with ID ${validatedData.clinicBranchId} not found`
14817
+ );
14736
14818
  }
14737
14819
  const clinic = clinicSnapshot.data();
14738
- const practitionerRef = (0, import_firestore45.doc)(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
14820
+ const practitionerRef = (0, import_firestore45.doc)(
14821
+ this.db,
14822
+ PRACTITIONERS_COLLECTION,
14823
+ validatedData.practitionerId
14824
+ );
14739
14825
  const practitionerSnapshot = await (0, import_firestore45.getDoc)(practitionerRef);
14740
14826
  if (!practitionerSnapshot.exists()) {
14741
- throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
14827
+ throw new Error(
14828
+ `Practitioner with ID ${validatedData.practitionerId} not found`
14829
+ );
14742
14830
  }
14743
14831
  const practitioner = practitionerSnapshot.data();
14744
14832
  let processedPhotos = [];
@@ -14769,6 +14857,7 @@ var ProcedureService = class extends BaseService {
14769
14857
  const newProcedure = {
14770
14858
  id: procedureId,
14771
14859
  ...validatedData,
14860
+ // Ensure nameLower is always set even if omitted by client
14772
14861
  nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
14773
14862
  photos: processedPhotos,
14774
14863
  category,
@@ -14778,7 +14867,9 @@ var ProcedureService = class extends BaseService {
14778
14867
  product,
14779
14868
  blockingConditions: technology.blockingConditions,
14780
14869
  contraindications: technology.contraindications || [],
14870
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
14781
14871
  treatmentBenefits: technology.benefits,
14872
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
14782
14873
  preRequirements: technology.requirements.pre,
14783
14874
  postRequirements: technology.requirements.post,
14784
14875
  certificationRequirement: technology.certificationRequirement,
@@ -14819,7 +14910,7 @@ var ProcedureService = class extends BaseService {
14819
14910
  * @returns A promise that resolves to an array of the newly created procedures.
14820
14911
  */
14821
14912
  async bulkCreateProcedures(baseData, practitionerIds) {
14822
- var _a;
14913
+ var _a, _b, _c;
14823
14914
  if (!practitionerIds || practitionerIds.length === 0) {
14824
14915
  throw new Error("Practitioner IDs array cannot be empty.");
14825
14916
  }
@@ -14827,16 +14918,24 @@ var ProcedureService = class extends BaseService {
14827
14918
  const validatedData = createProcedureSchema.parse(validationData);
14828
14919
  const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
14829
14920
  this.categoryService.getById(validatedData.categoryId),
14830
- this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
14921
+ this.subcategoryService.getById(
14922
+ validatedData.categoryId,
14923
+ validatedData.subcategoryId
14924
+ ),
14831
14925
  this.technologyService.getById(validatedData.technologyId),
14832
- this.productService.getById(validatedData.technologyId, validatedData.productId),
14926
+ this.productService.getById(
14927
+ validatedData.technologyId,
14928
+ validatedData.productId
14929
+ ),
14833
14930
  (0, import_firestore45.getDoc)((0, import_firestore45.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
14834
14931
  ]);
14835
14932
  if (!category || !subcategory || !technology || !product) {
14836
14933
  throw new Error("One or more required base entities not found");
14837
14934
  }
14838
14935
  if (!clinicSnapshot.exists()) {
14839
- throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
14936
+ throw new Error(
14937
+ `Clinic with ID ${validatedData.clinicBranchId} not found`
14938
+ );
14840
14939
  }
14841
14940
  const clinic = clinicSnapshot.data();
14842
14941
  let processedPhotos = [];
@@ -14862,8 +14961,12 @@ var ProcedureService = class extends BaseService {
14862
14961
  }
14863
14962
  if (practitionersMap.size !== practitionerIds.length) {
14864
14963
  const foundIds = Array.from(practitionersMap.keys());
14865
- const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
14866
- throw new Error(`The following practitioners were not found: ${notFoundIds.join(", ")}`);
14964
+ const notFoundIds = practitionerIds.filter(
14965
+ (id) => !foundIds.includes(id)
14966
+ );
14967
+ throw new Error(
14968
+ `The following practitioners were not found: ${notFoundIds.join(", ")}`
14969
+ );
14867
14970
  }
14868
14971
  const batch = (0, import_firestore45.writeBatch)(this.db);
14869
14972
  const createdProcedureIds = [];
@@ -14901,7 +15004,9 @@ var ProcedureService = class extends BaseService {
14901
15004
  product,
14902
15005
  blockingConditions: technology.blockingConditions,
14903
15006
  contraindications: technology.contraindications || [],
15007
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
14904
15008
  treatmentBenefits: technology.benefits,
15009
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
14905
15010
  preRequirements: technology.requirements.pre,
14906
15011
  postRequirements: technology.requirements.post,
14907
15012
  certificationRequirement: technology.certificationRequirement,
@@ -14931,7 +15036,10 @@ var ProcedureService = class extends BaseService {
14931
15036
  const fetchedProcedures = [];
14932
15037
  for (let i = 0; i < createdProcedureIds.length; i += 30) {
14933
15038
  const chunk = createdProcedureIds.slice(i, i + 30);
14934
- const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), (0, import_firestore45.where)((0, import_firestore45.documentId)(), "in", chunk));
15039
+ const q = (0, import_firestore45.query)(
15040
+ (0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION),
15041
+ (0, import_firestore45.where)((0, import_firestore45.documentId)(), "in", chunk)
15042
+ );
14935
15043
  const snapshot = await (0, import_firestore45.getDocs)(q);
14936
15044
  snapshot.forEach((doc37) => {
14937
15045
  fetchedProcedures.push(doc37.data());
@@ -15001,7 +15109,7 @@ var ProcedureService = class extends BaseService {
15001
15109
  * @returns The updated procedure
15002
15110
  */
15003
15111
  async updateProcedure(id, data) {
15004
- var _a;
15112
+ var _a, _b, _c;
15005
15113
  const validatedData = updateProcedureSchema.parse(data);
15006
15114
  const procedureRef = (0, import_firestore45.doc)(this.db, PROCEDURES_COLLECTION, id);
15007
15115
  const procedureSnapshot = await (0, import_firestore45.getDoc)(procedureRef);
@@ -15032,7 +15140,9 @@ var ProcedureService = class extends BaseService {
15032
15140
  );
15033
15141
  const newPractitionerSnap = await (0, import_firestore45.getDoc)(newPractitionerRef);
15034
15142
  if (!newPractitionerSnap.exists())
15035
- throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
15143
+ throw new Error(
15144
+ `New Practitioner ${validatedData.practitionerId} not found`
15145
+ );
15036
15146
  newPractitioner = newPractitionerSnap.data();
15037
15147
  updatedProcedureData.doctorInfo = {
15038
15148
  id: newPractitioner.id,
@@ -15046,7 +15156,11 @@ var ProcedureService = class extends BaseService {
15046
15156
  }
15047
15157
  if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
15048
15158
  clinicChanged = true;
15049
- const newClinicRef = (0, import_firestore45.doc)(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
15159
+ const newClinicRef = (0, import_firestore45.doc)(
15160
+ this.db,
15161
+ CLINICS_COLLECTION,
15162
+ validatedData.clinicBranchId
15163
+ );
15050
15164
  const newClinicSnap = await (0, import_firestore45.getDoc)(newClinicRef);
15051
15165
  if (!newClinicSnap.exists())
15052
15166
  throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
@@ -15065,8 +15179,11 @@ var ProcedureService = class extends BaseService {
15065
15179
  updatedProcedureData.nameLower = validatedData.name.toLowerCase();
15066
15180
  }
15067
15181
  if (validatedData.categoryId) {
15068
- const category = await this.categoryService.getById(validatedData.categoryId);
15069
- if (!category) throw new Error(`Category ${validatedData.categoryId} not found`);
15182
+ const category = await this.categoryService.getById(
15183
+ validatedData.categoryId
15184
+ );
15185
+ if (!category)
15186
+ throw new Error(`Category ${validatedData.categoryId} not found`);
15070
15187
  updatedProcedureData.category = category;
15071
15188
  finalCategoryId = category.id;
15072
15189
  }
@@ -15081,23 +15198,34 @@ var ProcedureService = class extends BaseService {
15081
15198
  );
15082
15199
  updatedProcedureData.subcategory = subcategory;
15083
15200
  } else if (validatedData.subcategoryId) {
15084
- console.warn("Attempted to update subcategory without a valid categoryId");
15201
+ console.warn(
15202
+ "Attempted to update subcategory without a valid categoryId"
15203
+ );
15085
15204
  }
15086
15205
  let finalTechnologyId = existingProcedure.technology.id;
15087
15206
  if (validatedData.technologyId) {
15088
- const technology = await this.technologyService.getById(validatedData.technologyId);
15089
- if (!technology) throw new Error(`Technology ${validatedData.technologyId} not found`);
15207
+ const technology = await this.technologyService.getById(
15208
+ validatedData.technologyId
15209
+ );
15210
+ if (!technology)
15211
+ throw new Error(`Technology ${validatedData.technologyId} not found`);
15090
15212
  updatedProcedureData.technology = technology;
15091
15213
  finalTechnologyId = technology.id;
15092
15214
  updatedProcedureData.blockingConditions = technology.blockingConditions;
15215
+ updatedProcedureData.contraindications = technology.contraindications || [];
15216
+ updatedProcedureData.contraindicationIds = ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [];
15093
15217
  updatedProcedureData.treatmentBenefits = technology.benefits;
15218
+ updatedProcedureData.treatmentBenefitIds = ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [];
15094
15219
  updatedProcedureData.preRequirements = technology.requirements.pre;
15095
15220
  updatedProcedureData.postRequirements = technology.requirements.post;
15096
15221
  updatedProcedureData.certificationRequirement = technology.certificationRequirement;
15097
15222
  updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
15098
15223
  }
15099
15224
  if (validatedData.productId && finalTechnologyId) {
15100
- const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
15225
+ const product = await this.productService.getById(
15226
+ finalTechnologyId,
15227
+ validatedData.productId
15228
+ );
15101
15229
  if (!product)
15102
15230
  throw new Error(
15103
15231
  `Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
@@ -15179,7 +15307,11 @@ var ProcedureService = class extends BaseService {
15179
15307
  limit16(pagination)
15180
15308
  );
15181
15309
  } else {
15182
- proceduresQuery = (0, import_firestore45.query)(proceduresCollection, (0, import_firestore45.orderBy)("name"), limit16(pagination));
15310
+ proceduresQuery = (0, import_firestore45.query)(
15311
+ proceduresCollection,
15312
+ (0, import_firestore45.orderBy)("name"),
15313
+ limit16(pagination)
15314
+ );
15183
15315
  }
15184
15316
  } else {
15185
15317
  proceduresQuery = (0, import_firestore45.query)(proceduresCollection, (0, import_firestore45.orderBy)("name"));
@@ -15210,7 +15342,7 @@ var ProcedureService = class extends BaseService {
15210
15342
  *
15211
15343
  * @param filters - Various filters to apply
15212
15344
  * @param filters.nameSearch - Optional search text for procedure name
15213
- * @param filters.treatmentBenefits - Optional array of treatment benefits to filter by
15345
+ * @param filters.treatmentBenefitIds - Optional array of treatment benefits to filter by
15214
15346
  * @param filters.procedureFamily - Optional procedure family to filter by
15215
15347
  * @param filters.procedureCategory - Optional procedure category to filter by
15216
15348
  * @param filters.procedureSubcategory - Optional procedure subcategory to filter by
@@ -15228,7 +15360,9 @@ var ProcedureService = class extends BaseService {
15228
15360
  */
15229
15361
  async getProceduresByFilters(filters) {
15230
15362
  try {
15231
- console.log("[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies");
15363
+ console.log(
15364
+ "[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies"
15365
+ );
15232
15366
  if (filters.location && filters.radiusInKm) {
15233
15367
  console.log("[PROCEDURE_SERVICE] Executing geo query:", {
15234
15368
  location: filters.location,
@@ -15236,7 +15370,10 @@ var ProcedureService = class extends BaseService {
15236
15370
  serviceName: "ProcedureService"
15237
15371
  });
15238
15372
  if (!filters.location.latitude || !filters.location.longitude) {
15239
- console.warn("[PROCEDURE_SERVICE] Invalid location data:", filters.location);
15373
+ console.warn(
15374
+ "[PROCEDURE_SERVICE] Invalid location data:",
15375
+ filters.location
15376
+ );
15240
15377
  filters.location = void 0;
15241
15378
  filters.radiusInKm = void 0;
15242
15379
  }
@@ -15256,13 +15393,19 @@ var ProcedureService = class extends BaseService {
15256
15393
  constraints.push((0, import_firestore45.where)("family", "==", filters.procedureFamily));
15257
15394
  }
15258
15395
  if (filters.procedureCategory) {
15259
- constraints.push((0, import_firestore45.where)("category.id", "==", filters.procedureCategory));
15396
+ constraints.push(
15397
+ (0, import_firestore45.where)("category.id", "==", filters.procedureCategory)
15398
+ );
15260
15399
  }
15261
15400
  if (filters.procedureSubcategory) {
15262
- constraints.push((0, import_firestore45.where)("subcategory.id", "==", filters.procedureSubcategory));
15401
+ constraints.push(
15402
+ (0, import_firestore45.where)("subcategory.id", "==", filters.procedureSubcategory)
15403
+ );
15263
15404
  }
15264
15405
  if (filters.procedureTechnology) {
15265
- constraints.push((0, import_firestore45.where)("technology.id", "==", filters.procedureTechnology));
15406
+ constraints.push(
15407
+ (0, import_firestore45.where)("technology.id", "==", filters.procedureTechnology)
15408
+ );
15266
15409
  }
15267
15410
  if (filters.minPrice !== void 0) {
15268
15411
  constraints.push((0, import_firestore45.where)("price", ">=", filters.minPrice));
@@ -15271,20 +15414,32 @@ var ProcedureService = class extends BaseService {
15271
15414
  constraints.push((0, import_firestore45.where)("price", "<=", filters.maxPrice));
15272
15415
  }
15273
15416
  if (filters.minRating !== void 0) {
15274
- constraints.push((0, import_firestore45.where)("reviewInfo.averageRating", ">=", filters.minRating));
15417
+ constraints.push(
15418
+ (0, import_firestore45.where)("reviewInfo.averageRating", ">=", filters.minRating)
15419
+ );
15275
15420
  }
15276
15421
  if (filters.maxRating !== void 0) {
15277
- constraints.push((0, import_firestore45.where)("reviewInfo.averageRating", "<=", filters.maxRating));
15422
+ constraints.push(
15423
+ (0, import_firestore45.where)("reviewInfo.averageRating", "<=", filters.maxRating)
15424
+ );
15278
15425
  }
15279
15426
  if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
15280
- const benefitsToMatch = filters.treatmentBenefits;
15281
- constraints.push((0, import_firestore45.where)("treatmentBenefits", "array-contains-any", benefitsToMatch));
15427
+ const benefitIdsToMatch = filters.treatmentBenefits;
15428
+ constraints.push(
15429
+ (0, import_firestore45.where)(
15430
+ "treatmentBenefitIds",
15431
+ "array-contains-any",
15432
+ benefitIdsToMatch
15433
+ )
15434
+ );
15282
15435
  }
15283
15436
  return constraints;
15284
15437
  };
15285
15438
  if (filters.nameSearch && filters.nameSearch.trim()) {
15286
15439
  try {
15287
- console.log("[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search");
15440
+ console.log(
15441
+ "[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search"
15442
+ );
15288
15443
  const searchTerm = filters.nameSearch.trim().toLowerCase();
15289
15444
  const constraints = getBaseConstraints();
15290
15445
  constraints.push((0, import_firestore45.where)("nameLower", ">=", searchTerm));
@@ -15300,13 +15455,18 @@ var ProcedureService = class extends BaseService {
15300
15455
  }
15301
15456
  }
15302
15457
  constraints.push((0, import_firestore45.limit)(filters.pagination || 10));
15303
- const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
15458
+ const q = (0, import_firestore45.query)(
15459
+ (0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION),
15460
+ ...constraints
15461
+ );
15304
15462
  const querySnapshot = await (0, import_firestore45.getDocs)(q);
15305
15463
  const procedures = querySnapshot.docs.map(
15306
15464
  (doc37) => ({ ...doc37.data(), id: doc37.id })
15307
15465
  );
15308
15466
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15309
- console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
15467
+ console.log(
15468
+ `[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`
15469
+ );
15310
15470
  if (procedures.length < (filters.pagination || 10)) {
15311
15471
  return { procedures, lastDoc: null };
15312
15472
  }
@@ -15317,7 +15477,9 @@ var ProcedureService = class extends BaseService {
15317
15477
  }
15318
15478
  if (filters.nameSearch && filters.nameSearch.trim()) {
15319
15479
  try {
15320
- console.log("[PROCEDURE_SERVICE] Strategy 2: Trying name field search");
15480
+ console.log(
15481
+ "[PROCEDURE_SERVICE] Strategy 2: Trying name field search"
15482
+ );
15321
15483
  const searchTerm = filters.nameSearch.trim().toLowerCase();
15322
15484
  const constraints = getBaseConstraints();
15323
15485
  constraints.push((0, import_firestore45.where)("name", ">=", searchTerm));
@@ -15333,13 +15495,18 @@ var ProcedureService = class extends BaseService {
15333
15495
  }
15334
15496
  }
15335
15497
  constraints.push((0, import_firestore45.limit)(filters.pagination || 10));
15336
- const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
15498
+ const q = (0, import_firestore45.query)(
15499
+ (0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION),
15500
+ ...constraints
15501
+ );
15337
15502
  const querySnapshot = await (0, import_firestore45.getDocs)(q);
15338
15503
  const procedures = querySnapshot.docs.map(
15339
15504
  (doc37) => ({ ...doc37.data(), id: doc37.id })
15340
15505
  );
15341
15506
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15342
- console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
15507
+ console.log(
15508
+ `[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`
15509
+ );
15343
15510
  if (procedures.length < (filters.pagination || 10)) {
15344
15511
  return { procedures, lastDoc: null };
15345
15512
  }
@@ -15364,14 +15531,19 @@ var ProcedureService = class extends BaseService {
15364
15531
  }
15365
15532
  }
15366
15533
  constraints.push((0, import_firestore45.limit)(filters.pagination || 10));
15367
- const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
15534
+ const q = (0, import_firestore45.query)(
15535
+ (0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION),
15536
+ ...constraints
15537
+ );
15368
15538
  const querySnapshot = await (0, import_firestore45.getDocs)(q);
15369
15539
  let procedures = querySnapshot.docs.map(
15370
15540
  (doc37) => ({ ...doc37.data(), id: doc37.id })
15371
15541
  );
15372
15542
  procedures = this.applyInMemoryFilters(procedures, filters);
15373
15543
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15374
- console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
15544
+ console.log(
15545
+ `[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`
15546
+ );
15375
15547
  if (procedures.length < (filters.pagination || 10)) {
15376
15548
  return { procedures, lastDoc: null };
15377
15549
  }
@@ -15386,14 +15558,19 @@ var ProcedureService = class extends BaseService {
15386
15558
  (0, import_firestore45.orderBy)("createdAt", "desc"),
15387
15559
  (0, import_firestore45.limit)(filters.pagination || 10)
15388
15560
  ];
15389
- const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
15561
+ const q = (0, import_firestore45.query)(
15562
+ (0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION),
15563
+ ...constraints
15564
+ );
15390
15565
  const querySnapshot = await (0, import_firestore45.getDocs)(q);
15391
15566
  let procedures = querySnapshot.docs.map(
15392
15567
  (doc37) => ({ ...doc37.data(), id: doc37.id })
15393
15568
  );
15394
15569
  procedures = this.applyInMemoryFilters(procedures, filters);
15395
15570
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15396
- console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
15571
+ console.log(
15572
+ `[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`
15573
+ );
15397
15574
  if (procedures.length < (filters.pagination || 10)) {
15398
15575
  return { procedures, lastDoc: null };
15399
15576
  }
@@ -15401,7 +15578,9 @@ var ProcedureService = class extends BaseService {
15401
15578
  } catch (error) {
15402
15579
  console.log("[PROCEDURE_SERVICE] Strategy 4 failed:", error);
15403
15580
  }
15404
- console.log("[PROCEDURE_SERVICE] All strategies failed, returning empty result");
15581
+ console.log(
15582
+ "[PROCEDURE_SERVICE] All strategies failed, returning empty result"
15583
+ );
15405
15584
  return { procedures: [], lastDoc: null };
15406
15585
  } catch (error) {
15407
15586
  console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
@@ -15421,13 +15600,17 @@ var ProcedureService = class extends BaseService {
15421
15600
  const nameLower = procedure.nameLower || "";
15422
15601
  return name.includes(searchTerm) || nameLower.includes(searchTerm);
15423
15602
  });
15424
- console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`);
15603
+ console.log(
15604
+ `[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`
15605
+ );
15425
15606
  }
15426
15607
  if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
15427
15608
  filteredProcedures = filteredProcedures.filter((procedure) => {
15428
15609
  const price = procedure.price || 0;
15429
- if (filters.minPrice !== void 0 && price < filters.minPrice) return false;
15430
- if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
15610
+ if (filters.minPrice !== void 0 && price < filters.minPrice)
15611
+ return false;
15612
+ if (filters.maxPrice !== void 0 && price > filters.maxPrice)
15613
+ return false;
15431
15614
  return true;
15432
15615
  });
15433
15616
  console.log(
@@ -15438,8 +15621,10 @@ var ProcedureService = class extends BaseService {
15438
15621
  filteredProcedures = filteredProcedures.filter((procedure) => {
15439
15622
  var _a;
15440
15623
  const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
15441
- if (filters.minRating !== void 0 && rating < filters.minRating) return false;
15442
- if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
15624
+ if (filters.minRating !== void 0 && rating < filters.minRating)
15625
+ return false;
15626
+ if (filters.maxRating !== void 0 && rating > filters.maxRating)
15627
+ return false;
15443
15628
  return true;
15444
15629
  });
15445
15630
  console.log(
@@ -15447,10 +15632,12 @@ var ProcedureService = class extends BaseService {
15447
15632
  );
15448
15633
  }
15449
15634
  if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
15450
- const benefitsToMatch = filters.treatmentBenefits;
15635
+ const benefitIdsToMatch = filters.treatmentBenefits;
15451
15636
  filteredProcedures = filteredProcedures.filter((procedure) => {
15452
- const procedureBenefits = procedure.treatmentBenefits || [];
15453
- return benefitsToMatch.some((benefit) => procedureBenefits.includes(benefit));
15637
+ const procedureBenefitIds = procedure.treatmentBenefitIds || [];
15638
+ return benefitIdsToMatch.some(
15639
+ (benefitId) => procedureBenefitIds.includes(benefitId)
15640
+ );
15454
15641
  });
15455
15642
  console.log(
15456
15643
  `[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
@@ -15513,8 +15700,12 @@ var ProcedureService = class extends BaseService {
15513
15700
  procedure.distance = distance;
15514
15701
  return distance <= radiusInKm;
15515
15702
  });
15516
- console.log(`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`);
15517
- filteredProcedures.sort((a, b) => (a.distance || 0) - (b.distance || 0));
15703
+ console.log(
15704
+ `[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`
15705
+ );
15706
+ filteredProcedures.sort(
15707
+ (a, b) => (a.distance || 0) - (b.distance || 0)
15708
+ );
15518
15709
  }
15519
15710
  return filteredProcedures;
15520
15711
  }
@@ -15526,19 +15717,30 @@ var ProcedureService = class extends BaseService {
15526
15717
  if (!location || !radiusInKm) {
15527
15718
  return Promise.resolve({ procedures: [], lastDoc: null });
15528
15719
  }
15529
- const bounds = (0, import_geofire_common8.geohashQueryBounds)([location.latitude, location.longitude], radiusInKm * 1e3);
15720
+ const bounds = (0, import_geofire_common8.geohashQueryBounds)(
15721
+ [location.latitude, location.longitude],
15722
+ radiusInKm * 1e3
15723
+ );
15530
15724
  const fetches = bounds.map((b) => {
15531
15725
  const constraints = [
15532
15726
  (0, import_firestore45.where)("clinicInfo.location.geohash", ">=", b[0]),
15533
15727
  (0, import_firestore45.where)("clinicInfo.location.geohash", "<=", b[1]),
15534
- (0, import_firestore45.where)("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
15728
+ (0, import_firestore45.where)(
15729
+ "isActive",
15730
+ "==",
15731
+ filters.isActive !== void 0 ? filters.isActive : true
15732
+ )
15535
15733
  ];
15536
- return (0, import_firestore45.getDocs)((0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints));
15734
+ return (0, import_firestore45.getDocs)(
15735
+ (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints)
15736
+ );
15537
15737
  });
15538
15738
  return Promise.all(fetches).then((snaps) => {
15539
15739
  const collected = [];
15540
15740
  snaps.forEach((snap) => {
15541
- snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
15741
+ snap.docs.forEach(
15742
+ (d) => collected.push({ ...d.data(), id: d.id })
15743
+ );
15542
15744
  });
15543
15745
  const uniqueMap = /* @__PURE__ */ new Map();
15544
15746
  for (const p of collected) {
@@ -15549,7 +15751,9 @@ var ProcedureService = class extends BaseService {
15549
15751
  const pageSize = filters.pagination || 10;
15550
15752
  let startIndex = 0;
15551
15753
  if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
15552
- const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
15754
+ const idx = procedures.findIndex(
15755
+ (p) => p.id === filters.lastDoc.id
15756
+ );
15553
15757
  if (idx >= 0) startIndex = idx + 1;
15554
15758
  }
15555
15759
  const page = procedures.slice(startIndex, startIndex + pageSize);
@@ -15574,7 +15778,7 @@ var ProcedureService = class extends BaseService {
15574
15778
  * @returns The created procedure
15575
15779
  */
15576
15780
  async createConsultationProcedure(data) {
15577
- var _a;
15781
+ var _a, _b, _c;
15578
15782
  const procedureId = this.generateId();
15579
15783
  const [category, subcategory, technology] = await Promise.all([
15580
15784
  this.categoryService.getById(data.categoryId),
@@ -15590,7 +15794,11 @@ var ProcedureService = class extends BaseService {
15590
15794
  throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
15591
15795
  }
15592
15796
  const clinic = clinicSnapshot.data();
15593
- const practitionerRef = (0, import_firestore45.doc)(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
15797
+ const practitionerRef = (0, import_firestore45.doc)(
15798
+ this.db,
15799
+ PRACTITIONERS_COLLECTION,
15800
+ data.practitionerId
15801
+ );
15594
15802
  const practitionerSnapshot = await (0, import_firestore45.getDoc)(practitionerRef);
15595
15803
  if (!practitionerSnapshot.exists()) {
15596
15804
  throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
@@ -15598,7 +15806,11 @@ var ProcedureService = class extends BaseService {
15598
15806
  const practitioner = practitionerSnapshot.data();
15599
15807
  let processedPhotos = [];
15600
15808
  if (data.photos && data.photos.length > 0) {
15601
- processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
15809
+ processedPhotos = await this.processMediaArray(
15810
+ data.photos,
15811
+ procedureId,
15812
+ "procedure-photos"
15813
+ );
15602
15814
  }
15603
15815
  const clinicInfo = {
15604
15816
  id: clinicSnapshot.id,
@@ -15640,7 +15852,9 @@ var ProcedureService = class extends BaseService {
15640
15852
  // Use placeholder product
15641
15853
  blockingConditions: technology.blockingConditions,
15642
15854
  contraindications: technology.contraindications || [],
15855
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
15643
15856
  treatmentBenefits: technology.benefits,
15857
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
15644
15858
  preRequirements: technology.requirements.pre,
15645
15859
  postRequirements: technology.requirements.post,
15646
15860
  certificationRequirement: technology.certificationRequirement,
@@ -15902,7 +16116,7 @@ var import_auth9 = require("firebase/auth");
15902
16116
  var import_analytics = require("firebase/analytics");
15903
16117
  var import_react_native = require("react-native");
15904
16118
  var import_storage4 = require("firebase/storage");
15905
- var import_functions2 = require("firebase/functions");
16119
+ var import_functions3 = require("firebase/functions");
15906
16120
  var firebaseInstance = null;
15907
16121
  var initializeFirebase = (config) => {
15908
16122
  if (!firebaseInstance) {
@@ -15910,7 +16124,7 @@ var initializeFirebase = (config) => {
15910
16124
  const db = (0, import_firestore47.getFirestore)(app);
15911
16125
  const auth = (0, import_auth9.getAuth)(app);
15912
16126
  const storage = (0, import_storage4.getStorage)(app);
15913
- const functions = (0, import_functions2.getFunctions)(app);
16127
+ const functions = (0, import_functions3.getFunctions)(app);
15914
16128
  let analytics = null;
15915
16129
  if (typeof window !== "undefined" && import_react_native.Platform.OS === "web") {
15916
16130
  analytics = (0, import_analytics.getAnalytics)(app);
@@ -16461,8 +16675,16 @@ var TechnologyService = class extends BaseService {
16461
16675
  */
16462
16676
  async addContraindication(technologyId, contraindication) {
16463
16677
  const docRef = (0, import_firestore51.doc)(this.getTechnologiesRef(), technologyId);
16678
+ const technology = await this.getById(technologyId);
16679
+ if (!technology) {
16680
+ throw new Error(`Technology with id ${technologyId} not found`);
16681
+ }
16682
+ const existingContraindications = technology.contraindications || [];
16683
+ if (existingContraindications.some((c) => c.id === contraindication.id)) {
16684
+ return technology;
16685
+ }
16464
16686
  await (0, import_firestore51.updateDoc)(docRef, {
16465
- contraindications: (0, import_firestore51.arrayUnion)(contraindication),
16687
+ contraindications: [...existingContraindications, contraindication],
16466
16688
  updatedAt: /* @__PURE__ */ new Date()
16467
16689
  });
16468
16690
  return this.getById(technologyId);
@@ -16475,8 +16697,44 @@ var TechnologyService = class extends BaseService {
16475
16697
  */
16476
16698
  async removeContraindication(technologyId, contraindication) {
16477
16699
  const docRef = (0, import_firestore51.doc)(this.getTechnologiesRef(), technologyId);
16700
+ const technology = await this.getById(technologyId);
16701
+ if (!technology) {
16702
+ throw new Error(`Technology with id ${technologyId} not found`);
16703
+ }
16704
+ const updatedContraindications = (technology.contraindications || []).filter((c) => c.id !== contraindication.id);
16478
16705
  await (0, import_firestore51.updateDoc)(docRef, {
16479
- contraindications: (0, import_firestore51.arrayRemove)(contraindication),
16706
+ contraindications: updatedContraindications,
16707
+ updatedAt: /* @__PURE__ */ new Date()
16708
+ });
16709
+ return this.getById(technologyId);
16710
+ }
16711
+ /**
16712
+ * Updates an existing contraindication in a technology's list.
16713
+ * If the contraindication does not exist, it will not be added.
16714
+ * @param technologyId - ID of the technology
16715
+ * @param contraindication - The updated contraindication object
16716
+ * @returns The updated technology
16717
+ */
16718
+ async updateContraindication(technologyId, contraindication) {
16719
+ const docRef = (0, import_firestore51.doc)(this.getTechnologiesRef(), technologyId);
16720
+ const technology = await this.getById(technologyId);
16721
+ if (!technology) {
16722
+ throw new Error(`Technology with id ${technologyId} not found`);
16723
+ }
16724
+ const contraindications = technology.contraindications || [];
16725
+ const index = contraindications.findIndex(
16726
+ (c) => c.id === contraindication.id
16727
+ );
16728
+ if (index === -1) {
16729
+ console.warn(
16730
+ `Contraindication with id ${contraindication.id} not found for technology ${technologyId}. No update performed.`
16731
+ );
16732
+ return technology;
16733
+ }
16734
+ const updatedContraindications = [...contraindications];
16735
+ updatedContraindications[index] = contraindication;
16736
+ await (0, import_firestore51.updateDoc)(docRef, {
16737
+ contraindications: updatedContraindications,
16480
16738
  updatedAt: /* @__PURE__ */ new Date()
16481
16739
  });
16482
16740
  return this.getById(technologyId);
@@ -16489,8 +16747,16 @@ var TechnologyService = class extends BaseService {
16489
16747
  */
16490
16748
  async addBenefit(technologyId, benefit) {
16491
16749
  const docRef = (0, import_firestore51.doc)(this.getTechnologiesRef(), technologyId);
16750
+ const technology = await this.getById(technologyId);
16751
+ if (!technology) {
16752
+ throw new Error(`Technology with id ${technologyId} not found`);
16753
+ }
16754
+ const existingBenefits = technology.benefits || [];
16755
+ if (existingBenefits.some((b) => b.id === benefit.id)) {
16756
+ return technology;
16757
+ }
16492
16758
  await (0, import_firestore51.updateDoc)(docRef, {
16493
- benefits: (0, import_firestore51.arrayUnion)(benefit),
16759
+ benefits: [...existingBenefits, benefit],
16494
16760
  updatedAt: /* @__PURE__ */ new Date()
16495
16761
  });
16496
16762
  return this.getById(technologyId);
@@ -16503,8 +16769,44 @@ var TechnologyService = class extends BaseService {
16503
16769
  */
16504
16770
  async removeBenefit(technologyId, benefit) {
16505
16771
  const docRef = (0, import_firestore51.doc)(this.getTechnologiesRef(), technologyId);
16772
+ const technology = await this.getById(technologyId);
16773
+ if (!technology) {
16774
+ throw new Error(`Technology with id ${technologyId} not found`);
16775
+ }
16776
+ const updatedBenefits = (technology.benefits || []).filter(
16777
+ (b) => b.id !== benefit.id
16778
+ );
16779
+ await (0, import_firestore51.updateDoc)(docRef, {
16780
+ benefits: updatedBenefits,
16781
+ updatedAt: /* @__PURE__ */ new Date()
16782
+ });
16783
+ return this.getById(technologyId);
16784
+ }
16785
+ /**
16786
+ * Updates an existing benefit in a technology's list.
16787
+ * If the benefit does not exist, it will not be added.
16788
+ * @param technologyId - ID of the technology
16789
+ * @param benefit - The updated benefit object
16790
+ * @returns The updated technology
16791
+ */
16792
+ async updateBenefit(technologyId, benefit) {
16793
+ const docRef = (0, import_firestore51.doc)(this.getTechnologiesRef(), technologyId);
16794
+ const technology = await this.getById(technologyId);
16795
+ if (!technology) {
16796
+ throw new Error(`Technology with id ${technologyId} not found`);
16797
+ }
16798
+ const benefits = technology.benefits || [];
16799
+ const index = benefits.findIndex((b) => b.id === benefit.id);
16800
+ if (index === -1) {
16801
+ console.warn(
16802
+ `Benefit with id ${benefit.id} not found for technology ${technologyId}. No update performed.`
16803
+ );
16804
+ return technology;
16805
+ }
16806
+ const updatedBenefits = [...benefits];
16807
+ updatedBenefits[index] = benefit;
16506
16808
  await (0, import_firestore51.updateDoc)(docRef, {
16507
- benefits: (0, import_firestore51.arrayRemove)(benefit),
16809
+ benefits: updatedBenefits,
16508
16810
  updatedAt: /* @__PURE__ */ new Date()
16509
16811
  });
16510
16812
  return this.getById(technologyId);
@@ -16758,6 +17060,23 @@ var ProductService = class extends BaseService {
16758
17060
  }
16759
17061
  };
16760
17062
 
17063
+ // src/backoffice/types/static/contraindication.types.ts
17064
+ var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
17065
+ Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
17066
+ Contraindication2["RECENT_TANNING"] = "recent_tanning";
17067
+ Contraindication2["RECENT_BOTOX"] = "recent_botox";
17068
+ Contraindication2["RECENT_FILLERS"] = "recent_fillers";
17069
+ Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
17070
+ Contraindication2["MEDICATIONS"] = "medications";
17071
+ Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
17072
+ Contraindication2["RECENT_LASER"] = "recent_laser";
17073
+ Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
17074
+ Contraindication2["OPEN_WOUNDS"] = "open_wounds";
17075
+ Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
17076
+ Contraindication2["COLD_SORES"] = "cold_sores";
17077
+ return Contraindication2;
17078
+ })(Contraindication || {});
17079
+
16761
17080
  // src/backoffice/types/static/treatment-benefit.types.ts
16762
17081
  var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
16763
17082
  TreatmentBenefit2["WRINKLE_REDUCTION"] = "wrinkle_reduction";