@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.mjs CHANGED
@@ -53,13 +53,13 @@ var AppointmentStatus = /* @__PURE__ */ ((AppointmentStatus2) => {
53
53
  AppointmentStatus2["RESCHEDULED_BY_CLINIC"] = "rescheduled_by_clinic";
54
54
  return AppointmentStatus2;
55
55
  })(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;
56
+ var PaymentStatus = /* @__PURE__ */ ((PaymentStatus4) => {
57
+ PaymentStatus4["UNPAID"] = "unpaid";
58
+ PaymentStatus4["PAID"] = "paid";
59
+ PaymentStatus4["PARTIALLY_PAID"] = "partially_paid";
60
+ PaymentStatus4["REFUNDED"] = "refunded";
61
+ PaymentStatus4["NOT_APPLICABLE"] = "not_applicable";
62
+ return PaymentStatus4;
63
63
  })(PaymentStatus || {});
64
64
  var MediaType = /* @__PURE__ */ ((MediaType2) => {
65
65
  MediaType2["BEFORE_PHOTO"] = "before_photo";
@@ -455,7 +455,8 @@ var createAppointmentSchema = z3.object({
455
455
  currency: z3.string().min(1, "Currency is required"),
456
456
  patientNotes: z3.string().max(MAX_STRING_LENGTH, "Patient notes too long").nullable().optional(),
457
457
  initialStatus: appointmentStatusSchema,
458
- initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */)
458
+ initialPaymentStatus: paymentStatusSchema.optional().default("unpaid" /* UNPAID */),
459
+ clinic_tz: z3.string().min(1, "Timezone is required")
459
460
  }).refine((data) => data.appointmentEndTime > data.appointmentStartTime, {
460
461
  message: "Appointment end time must be after start time",
461
462
  path: ["appointmentEndTime"]
@@ -489,6 +490,7 @@ var updateAppointmentSchema = z3.object({
489
490
  cost: z3.number().min(0).optional(),
490
491
  clinicBranchId: z3.string().min(MIN_STRING_LENGTH).optional(),
491
492
  practitionerId: z3.string().min(MIN_STRING_LENGTH).optional(),
493
+ clinic_tz: z3.string().min(MIN_STRING_LENGTH).optional(),
492
494
  linkedForms: z3.union([z3.array(linkedFormInfoSchema).max(MAX_ARRAY_LENGTH), z3.any()]).optional(),
493
495
  media: z3.union([
494
496
  z3.array(appointmentMediaItemSchema).max(MAX_ARRAY_LENGTH),
@@ -583,7 +585,6 @@ import {
583
585
  getDocs,
584
586
  query,
585
587
  where,
586
- setDoc,
587
588
  updateDoc,
588
589
  serverTimestamp,
589
590
  Timestamp,
@@ -820,44 +821,48 @@ async function updateAppointmentUtil(db, appointmentId, data) {
820
821
  const validPreReqIds = currentAppointment.preProcedureRequirements.map(
821
822
  (req) => req.id
822
823
  );
823
- const invalidPreReqIds = data.completedPreRequirements.filter(
824
- (id) => !validPreReqIds.includes(id)
825
- );
826
- if (invalidPreReqIds.length > 0) {
827
- throw new Error(
828
- `Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
824
+ if (Array.isArray(data.completedPreRequirements)) {
825
+ const invalidPreReqIds = data.completedPreRequirements.filter(
826
+ (id) => !validPreReqIds.includes(id)
829
827
  );
828
+ if (invalidPreReqIds.length > 0) {
829
+ throw new Error(
830
+ `Invalid pre-requirement IDs: ${invalidPreReqIds.join(", ")}`
831
+ );
832
+ }
833
+ completedPreRequirements = [
834
+ .../* @__PURE__ */ new Set([
835
+ ...completedPreRequirements,
836
+ ...data.completedPreRequirements
837
+ ])
838
+ ];
830
839
  }
831
- completedPreRequirements = [
832
- .../* @__PURE__ */ new Set([
833
- ...completedPreRequirements,
834
- ...data.completedPreRequirements
835
- ])
836
- ];
837
840
  }
838
841
  if (data.completedPostRequirements) {
839
842
  const validPostReqIds = currentAppointment.postProcedureRequirements.map(
840
843
  (req) => req.id
841
844
  );
842
- const invalidPostReqIds = data.completedPostRequirements.filter(
843
- (id) => !validPostReqIds.includes(id)
844
- );
845
- if (invalidPostReqIds.length > 0) {
846
- throw new Error(
847
- `Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
845
+ if (Array.isArray(data.completedPostRequirements)) {
846
+ const invalidPostReqIds = data.completedPostRequirements.filter(
847
+ (id) => !validPostReqIds.includes(id)
848
848
  );
849
+ if (invalidPostReqIds.length > 0) {
850
+ throw new Error(
851
+ `Invalid post-requirement IDs: ${invalidPostReqIds.join(", ")}`
852
+ );
853
+ }
854
+ completedPostRequirements = [
855
+ .../* @__PURE__ */ new Set([
856
+ ...completedPostRequirements,
857
+ ...data.completedPostRequirements
858
+ ])
859
+ ];
849
860
  }
850
- completedPostRequirements = [
851
- .../* @__PURE__ */ new Set([
852
- ...completedPostRequirements,
853
- ...data.completedPostRequirements
854
- ])
855
- ];
856
861
  }
857
862
  const updateData = {
858
863
  ...data,
859
- completedPreRequirements,
860
- completedPostRequirements,
864
+ completedPreRequirements: Array.isArray(data.completedPreRequirements) ? completedPreRequirements : data.completedPreRequirements,
865
+ completedPostRequirements: Array.isArray(data.completedPostRequirements) ? completedPostRequirements : data.completedPostRequirements,
861
866
  updatedAt: serverTimestamp()
862
867
  };
863
868
  Object.keys(updateData).forEach((key) => {
@@ -907,7 +912,7 @@ async function updateCalendarEventStatus(db, calendarEventId, appointmentStatus)
907
912
  case "canceled_clinic" /* CANCELED_CLINIC */:
908
913
  calendarStatus = "canceled";
909
914
  break;
910
- case AppointmentStatus.RESCHEDULED:
915
+ case "rescheduled_by_clinic" /* RESCHEDULED_BY_CLINIC */:
911
916
  calendarStatus = "rescheduled";
912
917
  break;
913
918
  case "completed" /* COMPLETED */:
@@ -2800,23 +2805,6 @@ var BlockingCondition = /* @__PURE__ */ ((BlockingCondition2) => {
2800
2805
  return BlockingCondition2;
2801
2806
  })(BlockingCondition || {});
2802
2807
 
2803
- // src/backoffice/types/static/contraindication.types.ts
2804
- var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
2805
- Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
2806
- Contraindication2["RECENT_TANNING"] = "recent_tanning";
2807
- Contraindication2["RECENT_BOTOX"] = "recent_botox";
2808
- Contraindication2["RECENT_FILLERS"] = "recent_fillers";
2809
- Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
2810
- Contraindication2["MEDICATIONS"] = "medications";
2811
- Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
2812
- Contraindication2["RECENT_LASER"] = "recent_laser";
2813
- Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
2814
- Contraindication2["OPEN_WOUNDS"] = "open_wounds";
2815
- Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
2816
- Contraindication2["COLD_SORES"] = "cold_sores";
2817
- return Contraindication2;
2818
- })(Contraindication || {});
2819
-
2820
2808
  // src/validations/common.schema.ts
2821
2809
  import { z as z5 } from "zod";
2822
2810
  import { Timestamp as Timestamp4 } from "firebase/firestore";
@@ -2871,8 +2859,13 @@ var blockingConditionSchema = z6.object({
2871
2859
  notes: z6.string().optional().nullable(),
2872
2860
  isActive: z6.boolean()
2873
2861
  });
2862
+ var contraindicationDynamicSchema = z6.object({
2863
+ id: z6.string(),
2864
+ name: z6.string(),
2865
+ description: z6.string().optional()
2866
+ });
2874
2867
  var contraindicationSchema = z6.object({
2875
- condition: z6.nativeEnum(Contraindication),
2868
+ condition: contraindicationDynamicSchema,
2876
2869
  lastOccurrence: timestampSchema,
2877
2870
  frequency: z6.enum(["rare", "occasional", "frequent"]),
2878
2871
  notes: z6.string().optional().nullable(),
@@ -3437,7 +3430,8 @@ var clinicLocationSchema = z10.object({
3437
3430
  postalCode: z10.string(),
3438
3431
  latitude: z10.number().min(-90).max(90),
3439
3432
  longitude: z10.number().min(-180).max(180),
3440
- geohash: z10.string().nullable().optional()
3433
+ geohash: z10.string().nullable().optional(),
3434
+ tz: z10.string().nullable().optional()
3441
3435
  });
3442
3436
  var workingHoursTimeSchema = z10.object({
3443
3437
  open: z10.string(),
@@ -3591,6 +3585,7 @@ var createClinicGroupSchema = z10.object({
3591
3585
  calendarSyncEnabled: z10.boolean().optional(),
3592
3586
  autoConfirmAppointments: z10.boolean().optional(),
3593
3587
  businessIdentificationNumber: z10.string().optional().nullable(),
3588
+ tz: z10.string().nullable().optional(),
3594
3589
  onboarding: z10.object({
3595
3590
  completed: z10.boolean().optional().default(false),
3596
3591
  step: z10.number().optional().default(1)
@@ -8342,7 +8337,10 @@ import {
8342
8337
  writeBatch as writeBatch4,
8343
8338
  arrayUnion as arrayUnion7
8344
8339
  } from "firebase/firestore";
8345
- import { geohashForLocation as geohashForLocation4 } from "geofire-common";
8340
+ import { getFunctions as getFunctions2, httpsCallable as httpsCallable2 } from "firebase/functions";
8341
+ import {
8342
+ geohashForLocation as geohashForLocation4
8343
+ } from "geofire-common";
8346
8344
  import { z as z20 } from "zod";
8347
8345
 
8348
8346
  // src/services/clinic/utils/clinic.utils.ts
@@ -9123,6 +9121,27 @@ var ClinicService = class extends BaseService {
9123
9121
  this.clinicAdminService = clinicAdminService;
9124
9122
  this.clinicGroupService = clinicGroupService;
9125
9123
  this.mediaService = mediaService;
9124
+ this.functions = getFunctions2(app);
9125
+ }
9126
+ /**
9127
+ * Get timezone from coordinates using the callable function
9128
+ * @param lat Latitude
9129
+ * @param lng Longitude
9130
+ * @returns IANA timezone string
9131
+ */
9132
+ async getTimezone(lat, lng) {
9133
+ try {
9134
+ const getTimezoneFromCoordinates = httpsCallable2(
9135
+ this.functions,
9136
+ "getTimezoneFromCoordinates"
9137
+ );
9138
+ const result = await getTimezoneFromCoordinates({ lat, lng });
9139
+ const data = result.data;
9140
+ return data.timezone;
9141
+ } catch (error) {
9142
+ console.error("Error getting timezone:", error);
9143
+ return null;
9144
+ }
9126
9145
  }
9127
9146
  /**
9128
9147
  * Process media resource (string URL or File object)
@@ -9137,7 +9156,9 @@ var ClinicService = class extends BaseService {
9137
9156
  return media;
9138
9157
  }
9139
9158
  if (media instanceof File || media instanceof Blob) {
9140
- console.log(`[ClinicService] Uploading ${collectionName} media for ${ownerId}`);
9159
+ console.log(
9160
+ `[ClinicService] Uploading ${collectionName} media for ${ownerId}`
9161
+ );
9141
9162
  const metadata = await this.mediaService.uploadMedia(
9142
9163
  media,
9143
9164
  ownerId,
@@ -9159,7 +9180,11 @@ var ClinicService = class extends BaseService {
9159
9180
  if (!mediaArray || mediaArray.length === 0) return [];
9160
9181
  const result = [];
9161
9182
  for (const media of mediaArray) {
9162
- const processedUrl = await this.processMedia(media, ownerId, collectionName);
9183
+ const processedUrl = await this.processMedia(
9184
+ media,
9185
+ ownerId,
9186
+ collectionName
9187
+ );
9163
9188
  if (processedUrl) {
9164
9189
  result.push(processedUrl);
9165
9190
  }
@@ -9177,7 +9202,11 @@ var ClinicService = class extends BaseService {
9177
9202
  if (!photosWithTags || photosWithTags.length === 0) return [];
9178
9203
  const result = [];
9179
9204
  for (const item of photosWithTags) {
9180
- const processedUrl = await this.processMedia(item.url, ownerId, collectionName);
9205
+ const processedUrl = await this.processMedia(
9206
+ item.url,
9207
+ ownerId,
9208
+ collectionName
9209
+ );
9181
9210
  if (processedUrl) {
9182
9211
  result.push({
9183
9212
  url: processedUrl,
@@ -9195,11 +9224,19 @@ var ClinicService = class extends BaseService {
9195
9224
  try {
9196
9225
  const clinicId = this.generateId();
9197
9226
  const validatedData = createClinicSchema.parse(data);
9198
- const group = await this.clinicGroupService.getClinicGroup(validatedData.clinicGroupId);
9227
+ const group = await this.clinicGroupService.getClinicGroup(
9228
+ validatedData.clinicGroupId
9229
+ );
9199
9230
  if (!group) {
9200
- throw new Error(`Clinic group ${validatedData.clinicGroupId} not found`);
9231
+ throw new Error(
9232
+ `Clinic group ${validatedData.clinicGroupId} not found`
9233
+ );
9201
9234
  }
9202
- const logoUrl = await this.processMedia(validatedData.logo, clinicId, "clinic-logos");
9235
+ const logoUrl = await this.processMedia(
9236
+ validatedData.logo,
9237
+ clinicId,
9238
+ "clinic-logos"
9239
+ );
9203
9240
  const coverPhotoUrl = await this.processMedia(
9204
9241
  validatedData.coverPhoto,
9205
9242
  clinicId,
@@ -9217,6 +9254,7 @@ var ClinicService = class extends BaseService {
9217
9254
  );
9218
9255
  const location = validatedData.location;
9219
9256
  const hash = geohashForLocation4([location.latitude, location.longitude]);
9257
+ const tz = await this.getTimezone(location.latitude, location.longitude);
9220
9258
  const defaultReviewInfo = {
9221
9259
  totalReviews: 0,
9222
9260
  averageRating: 0,
@@ -9234,7 +9272,7 @@ var ClinicService = class extends BaseService {
9234
9272
  nameLower: validatedData.name.toLowerCase(),
9235
9273
  // Add this line
9236
9274
  description: validatedData.description,
9237
- location: { ...location, geohash: hash },
9275
+ location: { ...location, geohash: hash, tz },
9238
9276
  contactInfo: validatedData.contactInfo,
9239
9277
  workingHours: validatedData.workingHours,
9240
9278
  tags: validatedData.tags,
@@ -9289,7 +9327,11 @@ var ClinicService = class extends BaseService {
9289
9327
  const validatedData = updateClinicSchema.parse(data);
9290
9328
  const updatePayload = {};
9291
9329
  if (validatedData.logo !== void 0) {
9292
- updatePayload.logo = await this.processMedia(validatedData.logo, clinicId, "clinic-logos");
9330
+ updatePayload.logo = await this.processMedia(
9331
+ validatedData.logo,
9332
+ clinicId,
9333
+ "clinic-logos"
9334
+ );
9293
9335
  }
9294
9336
  if (validatedData.coverPhoto !== void 0) {
9295
9337
  updatePayload.coverPhoto = await this.processMedia(
@@ -9334,9 +9376,11 @@ var ClinicService = class extends BaseService {
9334
9376
  }
9335
9377
  if (validatedData.location) {
9336
9378
  const loc = validatedData.location;
9379
+ const tz = await this.getTimezone(loc.latitude, loc.longitude);
9337
9380
  updatePayload.location = {
9338
9381
  ...loc,
9339
- geohash: geohashForLocation4([loc.latitude, loc.longitude])
9382
+ geohash: geohashForLocation4([loc.latitude, loc.longitude]),
9383
+ tz
9340
9384
  };
9341
9385
  }
9342
9386
  updatePayload.updatedAt = serverTimestamp14();
@@ -9389,10 +9433,22 @@ var ClinicService = class extends BaseService {
9389
9433
  * Pretražuje klinike u određenom radijusu
9390
9434
  */
9391
9435
  async findClinicsInRadius(center, radiusInKm, filters) {
9392
- return findClinicsInRadius(this.db, center, radiusInKm, filters);
9436
+ return findClinicsInRadius(
9437
+ this.db,
9438
+ center,
9439
+ radiusInKm,
9440
+ filters
9441
+ );
9393
9442
  }
9394
9443
  async addTags(clinicId, adminId, newTags) {
9395
- return addTags(this.db, clinicId, adminId, newTags, this.clinicAdminService, this.app);
9444
+ return addTags(
9445
+ this.db,
9446
+ clinicId,
9447
+ adminId,
9448
+ newTags,
9449
+ this.clinicAdminService,
9450
+ this.app
9451
+ );
9396
9452
  }
9397
9453
  async removeTags(clinicId, adminId, tagsToRemove) {
9398
9454
  return removeTags(
@@ -9430,7 +9486,9 @@ var ClinicService = class extends BaseService {
9430
9486
  clinicGroupId,
9431
9487
  adminId
9432
9488
  });
9433
- const clinicGroup = await this.clinicGroupService.getClinicGroup(clinicGroupId);
9489
+ const clinicGroup = await this.clinicGroupService.getClinicGroup(
9490
+ clinicGroupId
9491
+ );
9434
9492
  if (!clinicGroup) {
9435
9493
  console.error("[CLINIC_SERVICE] Clinic group not found", {
9436
9494
  clinicGroupId
@@ -9476,7 +9534,13 @@ var ClinicService = class extends BaseService {
9476
9534
  return getAllClinics(this.db, pagination, lastDoc);
9477
9535
  }
9478
9536
  async getAllClinicsInRange(center, rangeInKm, pagination, lastDoc) {
9479
- return getAllClinicsInRange(this.db, center, rangeInKm, pagination, lastDoc);
9537
+ return getAllClinicsInRange(
9538
+ this.db,
9539
+ center,
9540
+ rangeInKm,
9541
+ pagination,
9542
+ lastDoc
9543
+ );
9480
9544
  }
9481
9545
  /**
9482
9546
  * Get clinics based on multiple filtering criteria
@@ -10706,7 +10770,7 @@ async function updatePractitionerCalendarEventUtil(db, practitionerId, eventId,
10706
10770
  }
10707
10771
 
10708
10772
  // src/services/calendar/utils/appointment.utils.ts
10709
- async function createAppointmentUtil2(db, clinicId, practitionerId, patientId, eventData, generateId2) {
10773
+ async function createAppointmentUtil(db, clinicId, practitionerId, patientId, eventData, generateId2) {
10710
10774
  const eventId = generateId2();
10711
10775
  const autoConfirm = await checkAutoConfirmAppointmentsUtil(db, clinicId);
10712
10776
  const initialStatus = autoConfirm ? "confirmed" /* CONFIRMED */ : "pending" /* PENDING */;
@@ -12048,7 +12112,7 @@ var CalendarServiceV2 = class extends BaseService {
12048
12112
  syncStatus: "internal" /* INTERNAL */,
12049
12113
  eventType: "appointment" /* APPOINTMENT */
12050
12114
  };
12051
- const appointment = await createAppointmentUtil2(
12115
+ const appointment = await createAppointmentUtil(
12052
12116
  this.db,
12053
12117
  params.clinicId,
12054
12118
  params.doctorId,
@@ -14838,7 +14902,8 @@ import {
14838
14902
  import { z as z24 } from "zod";
14839
14903
  var createProcedureSchema = z24.object({
14840
14904
  name: z24.string().min(1).max(200),
14841
- nameLower: z24.string().min(1).max(200),
14905
+ // Optional: service will derive from name if not provided by client
14906
+ nameLower: z24.string().min(1).max(200).optional(),
14842
14907
  description: z24.string().min(1).max(2e3),
14843
14908
  family: z24.nativeEnum(ProcedureFamily),
14844
14909
  categoryId: z24.string().min(1),
@@ -14931,7 +14996,9 @@ var ProcedureService = class extends BaseService {
14931
14996
  return media;
14932
14997
  }
14933
14998
  if (media instanceof File || media instanceof Blob) {
14934
- console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
14999
+ console.log(
15000
+ `[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
15001
+ );
14935
15002
  const metadata = await this.mediaService.uploadMedia(
14936
15003
  media,
14937
15004
  ownerId,
@@ -14953,7 +15020,11 @@ var ProcedureService = class extends BaseService {
14953
15020
  if (!mediaArray || mediaArray.length === 0) return [];
14954
15021
  const result = [];
14955
15022
  for (const media of mediaArray) {
14956
- const processedUrl = await this.processMedia(media, ownerId, collectionName);
15023
+ const processedUrl = await this.processMedia(
15024
+ media,
15025
+ ownerId,
15026
+ collectionName
15027
+ );
14957
15028
  if (processedUrl) {
14958
15029
  result.push(processedUrl);
14959
15030
  }
@@ -14966,28 +15037,46 @@ var ProcedureService = class extends BaseService {
14966
15037
  * @returns The created procedure
14967
15038
  */
14968
15039
  async createProcedure(data) {
14969
- var _a;
15040
+ var _a, _b, _c;
14970
15041
  const validatedData = createProcedureSchema.parse(data);
14971
15042
  const procedureId = this.generateId();
14972
15043
  const [category, subcategory, technology, product] = await Promise.all([
14973
15044
  this.categoryService.getById(validatedData.categoryId),
14974
- this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
15045
+ this.subcategoryService.getById(
15046
+ validatedData.categoryId,
15047
+ validatedData.subcategoryId
15048
+ ),
14975
15049
  this.technologyService.getById(validatedData.technologyId),
14976
- this.productService.getById(validatedData.technologyId, validatedData.productId)
15050
+ this.productService.getById(
15051
+ validatedData.technologyId,
15052
+ validatedData.productId
15053
+ )
14977
15054
  ]);
14978
15055
  if (!category || !subcategory || !technology || !product) {
14979
15056
  throw new Error("One or more required base entities not found");
14980
15057
  }
14981
- const clinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
15058
+ const clinicRef = doc30(
15059
+ this.db,
15060
+ CLINICS_COLLECTION,
15061
+ validatedData.clinicBranchId
15062
+ );
14982
15063
  const clinicSnapshot = await getDoc32(clinicRef);
14983
15064
  if (!clinicSnapshot.exists()) {
14984
- throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
15065
+ throw new Error(
15066
+ `Clinic with ID ${validatedData.clinicBranchId} not found`
15067
+ );
14985
15068
  }
14986
15069
  const clinic = clinicSnapshot.data();
14987
- const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
15070
+ const practitionerRef = doc30(
15071
+ this.db,
15072
+ PRACTITIONERS_COLLECTION,
15073
+ validatedData.practitionerId
15074
+ );
14988
15075
  const practitionerSnapshot = await getDoc32(practitionerRef);
14989
15076
  if (!practitionerSnapshot.exists()) {
14990
- throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
15077
+ throw new Error(
15078
+ `Practitioner with ID ${validatedData.practitionerId} not found`
15079
+ );
14991
15080
  }
14992
15081
  const practitioner = practitionerSnapshot.data();
14993
15082
  let processedPhotos = [];
@@ -15018,6 +15107,7 @@ var ProcedureService = class extends BaseService {
15018
15107
  const newProcedure = {
15019
15108
  id: procedureId,
15020
15109
  ...validatedData,
15110
+ // Ensure nameLower is always set even if omitted by client
15021
15111
  nameLower: validatedData.nameLower || validatedData.name.toLowerCase(),
15022
15112
  photos: processedPhotos,
15023
15113
  category,
@@ -15027,7 +15117,9 @@ var ProcedureService = class extends BaseService {
15027
15117
  product,
15028
15118
  blockingConditions: technology.blockingConditions,
15029
15119
  contraindications: technology.contraindications || [],
15120
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
15030
15121
  treatmentBenefits: technology.benefits,
15122
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
15031
15123
  preRequirements: technology.requirements.pre,
15032
15124
  postRequirements: technology.requirements.post,
15033
15125
  certificationRequirement: technology.certificationRequirement,
@@ -15068,7 +15160,7 @@ var ProcedureService = class extends BaseService {
15068
15160
  * @returns A promise that resolves to an array of the newly created procedures.
15069
15161
  */
15070
15162
  async bulkCreateProcedures(baseData, practitionerIds) {
15071
- var _a;
15163
+ var _a, _b, _c;
15072
15164
  if (!practitionerIds || practitionerIds.length === 0) {
15073
15165
  throw new Error("Practitioner IDs array cannot be empty.");
15074
15166
  }
@@ -15076,16 +15168,24 @@ var ProcedureService = class extends BaseService {
15076
15168
  const validatedData = createProcedureSchema.parse(validationData);
15077
15169
  const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
15078
15170
  this.categoryService.getById(validatedData.categoryId),
15079
- this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
15171
+ this.subcategoryService.getById(
15172
+ validatedData.categoryId,
15173
+ validatedData.subcategoryId
15174
+ ),
15080
15175
  this.technologyService.getById(validatedData.technologyId),
15081
- this.productService.getById(validatedData.technologyId, validatedData.productId),
15176
+ this.productService.getById(
15177
+ validatedData.technologyId,
15178
+ validatedData.productId
15179
+ ),
15082
15180
  getDoc32(doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
15083
15181
  ]);
15084
15182
  if (!category || !subcategory || !technology || !product) {
15085
15183
  throw new Error("One or more required base entities not found");
15086
15184
  }
15087
15185
  if (!clinicSnapshot.exists()) {
15088
- throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
15186
+ throw new Error(
15187
+ `Clinic with ID ${validatedData.clinicBranchId} not found`
15188
+ );
15089
15189
  }
15090
15190
  const clinic = clinicSnapshot.data();
15091
15191
  let processedPhotos = [];
@@ -15111,8 +15211,12 @@ var ProcedureService = class extends BaseService {
15111
15211
  }
15112
15212
  if (practitionersMap.size !== practitionerIds.length) {
15113
15213
  const foundIds = Array.from(practitionersMap.keys());
15114
- const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
15115
- throw new Error(`The following practitioners were not found: ${notFoundIds.join(", ")}`);
15214
+ const notFoundIds = practitionerIds.filter(
15215
+ (id) => !foundIds.includes(id)
15216
+ );
15217
+ throw new Error(
15218
+ `The following practitioners were not found: ${notFoundIds.join(", ")}`
15219
+ );
15116
15220
  }
15117
15221
  const batch = writeBatch6(this.db);
15118
15222
  const createdProcedureIds = [];
@@ -15150,7 +15254,9 @@ var ProcedureService = class extends BaseService {
15150
15254
  product,
15151
15255
  blockingConditions: technology.blockingConditions,
15152
15256
  contraindications: technology.contraindications || [],
15257
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
15153
15258
  treatmentBenefits: technology.benefits,
15259
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
15154
15260
  preRequirements: technology.requirements.pre,
15155
15261
  postRequirements: technology.requirements.post,
15156
15262
  certificationRequirement: technology.certificationRequirement,
@@ -15180,7 +15286,10 @@ var ProcedureService = class extends BaseService {
15180
15286
  const fetchedProcedures = [];
15181
15287
  for (let i = 0; i < createdProcedureIds.length; i += 30) {
15182
15288
  const chunk = createdProcedureIds.slice(i, i + 30);
15183
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), where29(documentId2(), "in", chunk));
15289
+ const q = query29(
15290
+ collection29(this.db, PROCEDURES_COLLECTION),
15291
+ where29(documentId2(), "in", chunk)
15292
+ );
15184
15293
  const snapshot = await getDocs29(q);
15185
15294
  snapshot.forEach((doc37) => {
15186
15295
  fetchedProcedures.push(doc37.data());
@@ -15250,7 +15359,7 @@ var ProcedureService = class extends BaseService {
15250
15359
  * @returns The updated procedure
15251
15360
  */
15252
15361
  async updateProcedure(id, data) {
15253
- var _a;
15362
+ var _a, _b, _c;
15254
15363
  const validatedData = updateProcedureSchema.parse(data);
15255
15364
  const procedureRef = doc30(this.db, PROCEDURES_COLLECTION, id);
15256
15365
  const procedureSnapshot = await getDoc32(procedureRef);
@@ -15281,7 +15390,9 @@ var ProcedureService = class extends BaseService {
15281
15390
  );
15282
15391
  const newPractitionerSnap = await getDoc32(newPractitionerRef);
15283
15392
  if (!newPractitionerSnap.exists())
15284
- throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
15393
+ throw new Error(
15394
+ `New Practitioner ${validatedData.practitionerId} not found`
15395
+ );
15285
15396
  newPractitioner = newPractitionerSnap.data();
15286
15397
  updatedProcedureData.doctorInfo = {
15287
15398
  id: newPractitioner.id,
@@ -15295,7 +15406,11 @@ var ProcedureService = class extends BaseService {
15295
15406
  }
15296
15407
  if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
15297
15408
  clinicChanged = true;
15298
- const newClinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
15409
+ const newClinicRef = doc30(
15410
+ this.db,
15411
+ CLINICS_COLLECTION,
15412
+ validatedData.clinicBranchId
15413
+ );
15299
15414
  const newClinicSnap = await getDoc32(newClinicRef);
15300
15415
  if (!newClinicSnap.exists())
15301
15416
  throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
@@ -15314,8 +15429,11 @@ var ProcedureService = class extends BaseService {
15314
15429
  updatedProcedureData.nameLower = validatedData.name.toLowerCase();
15315
15430
  }
15316
15431
  if (validatedData.categoryId) {
15317
- const category = await this.categoryService.getById(validatedData.categoryId);
15318
- if (!category) throw new Error(`Category ${validatedData.categoryId} not found`);
15432
+ const category = await this.categoryService.getById(
15433
+ validatedData.categoryId
15434
+ );
15435
+ if (!category)
15436
+ throw new Error(`Category ${validatedData.categoryId} not found`);
15319
15437
  updatedProcedureData.category = category;
15320
15438
  finalCategoryId = category.id;
15321
15439
  }
@@ -15330,23 +15448,34 @@ var ProcedureService = class extends BaseService {
15330
15448
  );
15331
15449
  updatedProcedureData.subcategory = subcategory;
15332
15450
  } else if (validatedData.subcategoryId) {
15333
- console.warn("Attempted to update subcategory without a valid categoryId");
15451
+ console.warn(
15452
+ "Attempted to update subcategory without a valid categoryId"
15453
+ );
15334
15454
  }
15335
15455
  let finalTechnologyId = existingProcedure.technology.id;
15336
15456
  if (validatedData.technologyId) {
15337
- const technology = await this.technologyService.getById(validatedData.technologyId);
15338
- if (!technology) throw new Error(`Technology ${validatedData.technologyId} not found`);
15457
+ const technology = await this.technologyService.getById(
15458
+ validatedData.technologyId
15459
+ );
15460
+ if (!technology)
15461
+ throw new Error(`Technology ${validatedData.technologyId} not found`);
15339
15462
  updatedProcedureData.technology = technology;
15340
15463
  finalTechnologyId = technology.id;
15341
15464
  updatedProcedureData.blockingConditions = technology.blockingConditions;
15465
+ updatedProcedureData.contraindications = technology.contraindications || [];
15466
+ updatedProcedureData.contraindicationIds = ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [];
15342
15467
  updatedProcedureData.treatmentBenefits = technology.benefits;
15468
+ updatedProcedureData.treatmentBenefitIds = ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [];
15343
15469
  updatedProcedureData.preRequirements = technology.requirements.pre;
15344
15470
  updatedProcedureData.postRequirements = technology.requirements.post;
15345
15471
  updatedProcedureData.certificationRequirement = technology.certificationRequirement;
15346
15472
  updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
15347
15473
  }
15348
15474
  if (validatedData.productId && finalTechnologyId) {
15349
- const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
15475
+ const product = await this.productService.getById(
15476
+ finalTechnologyId,
15477
+ validatedData.productId
15478
+ );
15350
15479
  if (!product)
15351
15480
  throw new Error(
15352
15481
  `Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
@@ -15428,7 +15557,11 @@ var ProcedureService = class extends BaseService {
15428
15557
  limit16(pagination)
15429
15558
  );
15430
15559
  } else {
15431
- proceduresQuery = query29(proceduresCollection, orderBy17("name"), limit16(pagination));
15560
+ proceduresQuery = query29(
15561
+ proceduresCollection,
15562
+ orderBy17("name"),
15563
+ limit16(pagination)
15564
+ );
15432
15565
  }
15433
15566
  } else {
15434
15567
  proceduresQuery = query29(proceduresCollection, orderBy17("name"));
@@ -15459,7 +15592,7 @@ var ProcedureService = class extends BaseService {
15459
15592
  *
15460
15593
  * @param filters - Various filters to apply
15461
15594
  * @param filters.nameSearch - Optional search text for procedure name
15462
- * @param filters.treatmentBenefits - Optional array of treatment benefits to filter by
15595
+ * @param filters.treatmentBenefitIds - Optional array of treatment benefits to filter by
15463
15596
  * @param filters.procedureFamily - Optional procedure family to filter by
15464
15597
  * @param filters.procedureCategory - Optional procedure category to filter by
15465
15598
  * @param filters.procedureSubcategory - Optional procedure subcategory to filter by
@@ -15477,7 +15610,9 @@ var ProcedureService = class extends BaseService {
15477
15610
  */
15478
15611
  async getProceduresByFilters(filters) {
15479
15612
  try {
15480
- console.log("[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies");
15613
+ console.log(
15614
+ "[PROCEDURE_SERVICE] Starting procedure filtering with multiple strategies"
15615
+ );
15481
15616
  if (filters.location && filters.radiusInKm) {
15482
15617
  console.log("[PROCEDURE_SERVICE] Executing geo query:", {
15483
15618
  location: filters.location,
@@ -15485,7 +15620,10 @@ var ProcedureService = class extends BaseService {
15485
15620
  serviceName: "ProcedureService"
15486
15621
  });
15487
15622
  if (!filters.location.latitude || !filters.location.longitude) {
15488
- console.warn("[PROCEDURE_SERVICE] Invalid location data:", filters.location);
15623
+ console.warn(
15624
+ "[PROCEDURE_SERVICE] Invalid location data:",
15625
+ filters.location
15626
+ );
15489
15627
  filters.location = void 0;
15490
15628
  filters.radiusInKm = void 0;
15491
15629
  }
@@ -15505,13 +15643,19 @@ var ProcedureService = class extends BaseService {
15505
15643
  constraints.push(where29("family", "==", filters.procedureFamily));
15506
15644
  }
15507
15645
  if (filters.procedureCategory) {
15508
- constraints.push(where29("category.id", "==", filters.procedureCategory));
15646
+ constraints.push(
15647
+ where29("category.id", "==", filters.procedureCategory)
15648
+ );
15509
15649
  }
15510
15650
  if (filters.procedureSubcategory) {
15511
- constraints.push(where29("subcategory.id", "==", filters.procedureSubcategory));
15651
+ constraints.push(
15652
+ where29("subcategory.id", "==", filters.procedureSubcategory)
15653
+ );
15512
15654
  }
15513
15655
  if (filters.procedureTechnology) {
15514
- constraints.push(where29("technology.id", "==", filters.procedureTechnology));
15656
+ constraints.push(
15657
+ where29("technology.id", "==", filters.procedureTechnology)
15658
+ );
15515
15659
  }
15516
15660
  if (filters.minPrice !== void 0) {
15517
15661
  constraints.push(where29("price", ">=", filters.minPrice));
@@ -15520,20 +15664,32 @@ var ProcedureService = class extends BaseService {
15520
15664
  constraints.push(where29("price", "<=", filters.maxPrice));
15521
15665
  }
15522
15666
  if (filters.minRating !== void 0) {
15523
- constraints.push(where29("reviewInfo.averageRating", ">=", filters.minRating));
15667
+ constraints.push(
15668
+ where29("reviewInfo.averageRating", ">=", filters.minRating)
15669
+ );
15524
15670
  }
15525
15671
  if (filters.maxRating !== void 0) {
15526
- constraints.push(where29("reviewInfo.averageRating", "<=", filters.maxRating));
15672
+ constraints.push(
15673
+ where29("reviewInfo.averageRating", "<=", filters.maxRating)
15674
+ );
15527
15675
  }
15528
15676
  if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
15529
- const benefitsToMatch = filters.treatmentBenefits;
15530
- constraints.push(where29("treatmentBenefits", "array-contains-any", benefitsToMatch));
15677
+ const benefitIdsToMatch = filters.treatmentBenefits;
15678
+ constraints.push(
15679
+ where29(
15680
+ "treatmentBenefitIds",
15681
+ "array-contains-any",
15682
+ benefitIdsToMatch
15683
+ )
15684
+ );
15531
15685
  }
15532
15686
  return constraints;
15533
15687
  };
15534
15688
  if (filters.nameSearch && filters.nameSearch.trim()) {
15535
15689
  try {
15536
- console.log("[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search");
15690
+ console.log(
15691
+ "[PROCEDURE_SERVICE] Strategy 1: Trying nameLower search"
15692
+ );
15537
15693
  const searchTerm = filters.nameSearch.trim().toLowerCase();
15538
15694
  const constraints = getBaseConstraints();
15539
15695
  constraints.push(where29("nameLower", ">=", searchTerm));
@@ -15549,13 +15705,18 @@ var ProcedureService = class extends BaseService {
15549
15705
  }
15550
15706
  }
15551
15707
  constraints.push(limit15(filters.pagination || 10));
15552
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15708
+ const q = query29(
15709
+ collection29(this.db, PROCEDURES_COLLECTION),
15710
+ ...constraints
15711
+ );
15553
15712
  const querySnapshot = await getDocs29(q);
15554
15713
  const procedures = querySnapshot.docs.map(
15555
15714
  (doc37) => ({ ...doc37.data(), id: doc37.id })
15556
15715
  );
15557
15716
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15558
- console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
15717
+ console.log(
15718
+ `[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`
15719
+ );
15559
15720
  if (procedures.length < (filters.pagination || 10)) {
15560
15721
  return { procedures, lastDoc: null };
15561
15722
  }
@@ -15566,7 +15727,9 @@ var ProcedureService = class extends BaseService {
15566
15727
  }
15567
15728
  if (filters.nameSearch && filters.nameSearch.trim()) {
15568
15729
  try {
15569
- console.log("[PROCEDURE_SERVICE] Strategy 2: Trying name field search");
15730
+ console.log(
15731
+ "[PROCEDURE_SERVICE] Strategy 2: Trying name field search"
15732
+ );
15570
15733
  const searchTerm = filters.nameSearch.trim().toLowerCase();
15571
15734
  const constraints = getBaseConstraints();
15572
15735
  constraints.push(where29("name", ">=", searchTerm));
@@ -15582,13 +15745,18 @@ var ProcedureService = class extends BaseService {
15582
15745
  }
15583
15746
  }
15584
15747
  constraints.push(limit15(filters.pagination || 10));
15585
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15748
+ const q = query29(
15749
+ collection29(this.db, PROCEDURES_COLLECTION),
15750
+ ...constraints
15751
+ );
15586
15752
  const querySnapshot = await getDocs29(q);
15587
15753
  const procedures = querySnapshot.docs.map(
15588
15754
  (doc37) => ({ ...doc37.data(), id: doc37.id })
15589
15755
  );
15590
15756
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15591
- console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
15757
+ console.log(
15758
+ `[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`
15759
+ );
15592
15760
  if (procedures.length < (filters.pagination || 10)) {
15593
15761
  return { procedures, lastDoc: null };
15594
15762
  }
@@ -15613,14 +15781,19 @@ var ProcedureService = class extends BaseService {
15613
15781
  }
15614
15782
  }
15615
15783
  constraints.push(limit15(filters.pagination || 10));
15616
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15784
+ const q = query29(
15785
+ collection29(this.db, PROCEDURES_COLLECTION),
15786
+ ...constraints
15787
+ );
15617
15788
  const querySnapshot = await getDocs29(q);
15618
15789
  let procedures = querySnapshot.docs.map(
15619
15790
  (doc37) => ({ ...doc37.data(), id: doc37.id })
15620
15791
  );
15621
15792
  procedures = this.applyInMemoryFilters(procedures, filters);
15622
15793
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15623
- console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
15794
+ console.log(
15795
+ `[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`
15796
+ );
15624
15797
  if (procedures.length < (filters.pagination || 10)) {
15625
15798
  return { procedures, lastDoc: null };
15626
15799
  }
@@ -15635,14 +15808,19 @@ var ProcedureService = class extends BaseService {
15635
15808
  orderBy17("createdAt", "desc"),
15636
15809
  limit15(filters.pagination || 10)
15637
15810
  ];
15638
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15811
+ const q = query29(
15812
+ collection29(this.db, PROCEDURES_COLLECTION),
15813
+ ...constraints
15814
+ );
15639
15815
  const querySnapshot = await getDocs29(q);
15640
15816
  let procedures = querySnapshot.docs.map(
15641
15817
  (doc37) => ({ ...doc37.data(), id: doc37.id })
15642
15818
  );
15643
15819
  procedures = this.applyInMemoryFilters(procedures, filters);
15644
15820
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15645
- console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
15821
+ console.log(
15822
+ `[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`
15823
+ );
15646
15824
  if (procedures.length < (filters.pagination || 10)) {
15647
15825
  return { procedures, lastDoc: null };
15648
15826
  }
@@ -15650,7 +15828,9 @@ var ProcedureService = class extends BaseService {
15650
15828
  } catch (error) {
15651
15829
  console.log("[PROCEDURE_SERVICE] Strategy 4 failed:", error);
15652
15830
  }
15653
- console.log("[PROCEDURE_SERVICE] All strategies failed, returning empty result");
15831
+ console.log(
15832
+ "[PROCEDURE_SERVICE] All strategies failed, returning empty result"
15833
+ );
15654
15834
  return { procedures: [], lastDoc: null };
15655
15835
  } catch (error) {
15656
15836
  console.error("[PROCEDURE_SERVICE] Error filtering procedures:", error);
@@ -15670,13 +15850,17 @@ var ProcedureService = class extends BaseService {
15670
15850
  const nameLower = procedure.nameLower || "";
15671
15851
  return name.includes(searchTerm) || nameLower.includes(searchTerm);
15672
15852
  });
15673
- console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`);
15853
+ console.log(
15854
+ `[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`
15855
+ );
15674
15856
  }
15675
15857
  if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
15676
15858
  filteredProcedures = filteredProcedures.filter((procedure) => {
15677
15859
  const price = procedure.price || 0;
15678
- if (filters.minPrice !== void 0 && price < filters.minPrice) return false;
15679
- if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
15860
+ if (filters.minPrice !== void 0 && price < filters.minPrice)
15861
+ return false;
15862
+ if (filters.maxPrice !== void 0 && price > filters.maxPrice)
15863
+ return false;
15680
15864
  return true;
15681
15865
  });
15682
15866
  console.log(
@@ -15687,8 +15871,10 @@ var ProcedureService = class extends BaseService {
15687
15871
  filteredProcedures = filteredProcedures.filter((procedure) => {
15688
15872
  var _a;
15689
15873
  const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
15690
- if (filters.minRating !== void 0 && rating < filters.minRating) return false;
15691
- if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
15874
+ if (filters.minRating !== void 0 && rating < filters.minRating)
15875
+ return false;
15876
+ if (filters.maxRating !== void 0 && rating > filters.maxRating)
15877
+ return false;
15692
15878
  return true;
15693
15879
  });
15694
15880
  console.log(
@@ -15696,10 +15882,12 @@ var ProcedureService = class extends BaseService {
15696
15882
  );
15697
15883
  }
15698
15884
  if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
15699
- const benefitsToMatch = filters.treatmentBenefits;
15885
+ const benefitIdsToMatch = filters.treatmentBenefits;
15700
15886
  filteredProcedures = filteredProcedures.filter((procedure) => {
15701
- const procedureBenefits = procedure.treatmentBenefits || [];
15702
- return benefitsToMatch.some((benefit) => procedureBenefits.includes(benefit));
15887
+ const procedureBenefitIds = procedure.treatmentBenefitIds || [];
15888
+ return benefitIdsToMatch.some(
15889
+ (benefitId) => procedureBenefitIds.includes(benefitId)
15890
+ );
15703
15891
  });
15704
15892
  console.log(
15705
15893
  `[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
@@ -15762,8 +15950,12 @@ var ProcedureService = class extends BaseService {
15762
15950
  procedure.distance = distance;
15763
15951
  return distance <= radiusInKm;
15764
15952
  });
15765
- console.log(`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`);
15766
- filteredProcedures.sort((a, b) => (a.distance || 0) - (b.distance || 0));
15953
+ console.log(
15954
+ `[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`
15955
+ );
15956
+ filteredProcedures.sort(
15957
+ (a, b) => (a.distance || 0) - (b.distance || 0)
15958
+ );
15767
15959
  }
15768
15960
  return filteredProcedures;
15769
15961
  }
@@ -15775,19 +15967,30 @@ var ProcedureService = class extends BaseService {
15775
15967
  if (!location || !radiusInKm) {
15776
15968
  return Promise.resolve({ procedures: [], lastDoc: null });
15777
15969
  }
15778
- const bounds = geohashQueryBounds5([location.latitude, location.longitude], radiusInKm * 1e3);
15970
+ const bounds = geohashQueryBounds5(
15971
+ [location.latitude, location.longitude],
15972
+ radiusInKm * 1e3
15973
+ );
15779
15974
  const fetches = bounds.map((b) => {
15780
15975
  const constraints = [
15781
15976
  where29("clinicInfo.location.geohash", ">=", b[0]),
15782
15977
  where29("clinicInfo.location.geohash", "<=", b[1]),
15783
- where29("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
15978
+ where29(
15979
+ "isActive",
15980
+ "==",
15981
+ filters.isActive !== void 0 ? filters.isActive : true
15982
+ )
15784
15983
  ];
15785
- return getDocs29(query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints));
15984
+ return getDocs29(
15985
+ query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints)
15986
+ );
15786
15987
  });
15787
15988
  return Promise.all(fetches).then((snaps) => {
15788
15989
  const collected = [];
15789
15990
  snaps.forEach((snap) => {
15790
- snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
15991
+ snap.docs.forEach(
15992
+ (d) => collected.push({ ...d.data(), id: d.id })
15993
+ );
15791
15994
  });
15792
15995
  const uniqueMap = /* @__PURE__ */ new Map();
15793
15996
  for (const p of collected) {
@@ -15798,7 +16001,9 @@ var ProcedureService = class extends BaseService {
15798
16001
  const pageSize = filters.pagination || 10;
15799
16002
  let startIndex = 0;
15800
16003
  if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
15801
- const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
16004
+ const idx = procedures.findIndex(
16005
+ (p) => p.id === filters.lastDoc.id
16006
+ );
15802
16007
  if (idx >= 0) startIndex = idx + 1;
15803
16008
  }
15804
16009
  const page = procedures.slice(startIndex, startIndex + pageSize);
@@ -15823,7 +16028,7 @@ var ProcedureService = class extends BaseService {
15823
16028
  * @returns The created procedure
15824
16029
  */
15825
16030
  async createConsultationProcedure(data) {
15826
- var _a;
16031
+ var _a, _b, _c;
15827
16032
  const procedureId = this.generateId();
15828
16033
  const [category, subcategory, technology] = await Promise.all([
15829
16034
  this.categoryService.getById(data.categoryId),
@@ -15839,7 +16044,11 @@ var ProcedureService = class extends BaseService {
15839
16044
  throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
15840
16045
  }
15841
16046
  const clinic = clinicSnapshot.data();
15842
- const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
16047
+ const practitionerRef = doc30(
16048
+ this.db,
16049
+ PRACTITIONERS_COLLECTION,
16050
+ data.practitionerId
16051
+ );
15843
16052
  const practitionerSnapshot = await getDoc32(practitionerRef);
15844
16053
  if (!practitionerSnapshot.exists()) {
15845
16054
  throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
@@ -15847,7 +16056,11 @@ var ProcedureService = class extends BaseService {
15847
16056
  const practitioner = practitionerSnapshot.data();
15848
16057
  let processedPhotos = [];
15849
16058
  if (data.photos && data.photos.length > 0) {
15850
- processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
16059
+ processedPhotos = await this.processMediaArray(
16060
+ data.photos,
16061
+ procedureId,
16062
+ "procedure-photos"
16063
+ );
15851
16064
  }
15852
16065
  const clinicInfo = {
15853
16066
  id: clinicSnapshot.id,
@@ -15889,7 +16102,9 @@ var ProcedureService = class extends BaseService {
15889
16102
  // Use placeholder product
15890
16103
  blockingConditions: technology.blockingConditions,
15891
16104
  contraindications: technology.contraindications || [],
16105
+ contraindicationIds: ((_b = technology.contraindications) == null ? void 0 : _b.map((c) => c.id)) || [],
15892
16106
  treatmentBenefits: technology.benefits,
16107
+ treatmentBenefitIds: ((_c = technology.benefits) == null ? void 0 : _c.map((b) => b.id)) || [],
15893
16108
  preRequirements: technology.requirements.pre,
15894
16109
  postRequirements: technology.requirements.post,
15895
16110
  certificationRequirement: technology.certificationRequirement,
@@ -16161,7 +16376,7 @@ import { getAuth } from "firebase/auth";
16161
16376
  import { getAnalytics } from "firebase/analytics";
16162
16377
  import { Platform } from "react-native";
16163
16378
  import { getStorage as getStorage3 } from "firebase/storage";
16164
- import { getFunctions as getFunctions2 } from "firebase/functions";
16379
+ import { getFunctions as getFunctions3 } from "firebase/functions";
16165
16380
  var firebaseInstance = null;
16166
16381
  var initializeFirebase = (config) => {
16167
16382
  if (!firebaseInstance) {
@@ -16169,7 +16384,7 @@ var initializeFirebase = (config) => {
16169
16384
  const db = getFirestore2(app);
16170
16385
  const auth = getAuth(app);
16171
16386
  const storage = getStorage3(app);
16172
- const functions = getFunctions2(app);
16387
+ const functions = getFunctions3(app);
16173
16388
  let analytics = null;
16174
16389
  if (typeof window !== "undefined" && Platform.OS === "web") {
16175
16390
  analytics = getAnalytics(app);
@@ -16758,8 +16973,16 @@ var TechnologyService = class extends BaseService {
16758
16973
  */
16759
16974
  async addContraindication(technologyId, contraindication) {
16760
16975
  const docRef = doc35(this.getTechnologiesRef(), technologyId);
16976
+ const technology = await this.getById(technologyId);
16977
+ if (!technology) {
16978
+ throw new Error(`Technology with id ${technologyId} not found`);
16979
+ }
16980
+ const existingContraindications = technology.contraindications || [];
16981
+ if (existingContraindications.some((c) => c.id === contraindication.id)) {
16982
+ return technology;
16983
+ }
16761
16984
  await updateDoc33(docRef, {
16762
- contraindications: arrayUnion9(contraindication),
16985
+ contraindications: [...existingContraindications, contraindication],
16763
16986
  updatedAt: /* @__PURE__ */ new Date()
16764
16987
  });
16765
16988
  return this.getById(technologyId);
@@ -16772,8 +16995,44 @@ var TechnologyService = class extends BaseService {
16772
16995
  */
16773
16996
  async removeContraindication(technologyId, contraindication) {
16774
16997
  const docRef = doc35(this.getTechnologiesRef(), technologyId);
16998
+ const technology = await this.getById(technologyId);
16999
+ if (!technology) {
17000
+ throw new Error(`Technology with id ${technologyId} not found`);
17001
+ }
17002
+ const updatedContraindications = (technology.contraindications || []).filter((c) => c.id !== contraindication.id);
16775
17003
  await updateDoc33(docRef, {
16776
- contraindications: arrayRemove8(contraindication),
17004
+ contraindications: updatedContraindications,
17005
+ updatedAt: /* @__PURE__ */ new Date()
17006
+ });
17007
+ return this.getById(technologyId);
17008
+ }
17009
+ /**
17010
+ * Updates an existing contraindication in a technology's list.
17011
+ * If the contraindication does not exist, it will not be added.
17012
+ * @param technologyId - ID of the technology
17013
+ * @param contraindication - The updated contraindication object
17014
+ * @returns The updated technology
17015
+ */
17016
+ async updateContraindication(technologyId, contraindication) {
17017
+ const docRef = doc35(this.getTechnologiesRef(), technologyId);
17018
+ const technology = await this.getById(technologyId);
17019
+ if (!technology) {
17020
+ throw new Error(`Technology with id ${technologyId} not found`);
17021
+ }
17022
+ const contraindications = technology.contraindications || [];
17023
+ const index = contraindications.findIndex(
17024
+ (c) => c.id === contraindication.id
17025
+ );
17026
+ if (index === -1) {
17027
+ console.warn(
17028
+ `Contraindication with id ${contraindication.id} not found for technology ${technologyId}. No update performed.`
17029
+ );
17030
+ return technology;
17031
+ }
17032
+ const updatedContraindications = [...contraindications];
17033
+ updatedContraindications[index] = contraindication;
17034
+ await updateDoc33(docRef, {
17035
+ contraindications: updatedContraindications,
16777
17036
  updatedAt: /* @__PURE__ */ new Date()
16778
17037
  });
16779
17038
  return this.getById(technologyId);
@@ -16786,8 +17045,16 @@ var TechnologyService = class extends BaseService {
16786
17045
  */
16787
17046
  async addBenefit(technologyId, benefit) {
16788
17047
  const docRef = doc35(this.getTechnologiesRef(), technologyId);
17048
+ const technology = await this.getById(technologyId);
17049
+ if (!technology) {
17050
+ throw new Error(`Technology with id ${technologyId} not found`);
17051
+ }
17052
+ const existingBenefits = technology.benefits || [];
17053
+ if (existingBenefits.some((b) => b.id === benefit.id)) {
17054
+ return technology;
17055
+ }
16789
17056
  await updateDoc33(docRef, {
16790
- benefits: arrayUnion9(benefit),
17057
+ benefits: [...existingBenefits, benefit],
16791
17058
  updatedAt: /* @__PURE__ */ new Date()
16792
17059
  });
16793
17060
  return this.getById(technologyId);
@@ -16800,8 +17067,44 @@ var TechnologyService = class extends BaseService {
16800
17067
  */
16801
17068
  async removeBenefit(technologyId, benefit) {
16802
17069
  const docRef = doc35(this.getTechnologiesRef(), technologyId);
17070
+ const technology = await this.getById(technologyId);
17071
+ if (!technology) {
17072
+ throw new Error(`Technology with id ${technologyId} not found`);
17073
+ }
17074
+ const updatedBenefits = (technology.benefits || []).filter(
17075
+ (b) => b.id !== benefit.id
17076
+ );
17077
+ await updateDoc33(docRef, {
17078
+ benefits: updatedBenefits,
17079
+ updatedAt: /* @__PURE__ */ new Date()
17080
+ });
17081
+ return this.getById(technologyId);
17082
+ }
17083
+ /**
17084
+ * Updates an existing benefit in a technology's list.
17085
+ * If the benefit does not exist, it will not be added.
17086
+ * @param technologyId - ID of the technology
17087
+ * @param benefit - The updated benefit object
17088
+ * @returns The updated technology
17089
+ */
17090
+ async updateBenefit(technologyId, benefit) {
17091
+ const docRef = doc35(this.getTechnologiesRef(), technologyId);
17092
+ const technology = await this.getById(technologyId);
17093
+ if (!technology) {
17094
+ throw new Error(`Technology with id ${technologyId} not found`);
17095
+ }
17096
+ const benefits = technology.benefits || [];
17097
+ const index = benefits.findIndex((b) => b.id === benefit.id);
17098
+ if (index === -1) {
17099
+ console.warn(
17100
+ `Benefit with id ${benefit.id} not found for technology ${technologyId}. No update performed.`
17101
+ );
17102
+ return technology;
17103
+ }
17104
+ const updatedBenefits = [...benefits];
17105
+ updatedBenefits[index] = benefit;
16803
17106
  await updateDoc33(docRef, {
16804
- benefits: arrayRemove8(benefit),
17107
+ benefits: updatedBenefits,
16805
17108
  updatedAt: /* @__PURE__ */ new Date()
16806
17109
  });
16807
17110
  return this.getById(technologyId);
@@ -17064,6 +17367,23 @@ var ProductService = class extends BaseService {
17064
17367
  }
17065
17368
  };
17066
17369
 
17370
+ // src/backoffice/types/static/contraindication.types.ts
17371
+ var Contraindication = /* @__PURE__ */ ((Contraindication2) => {
17372
+ Contraindication2["SENSITIVE_SKIN"] = "sensitive_skin";
17373
+ Contraindication2["RECENT_TANNING"] = "recent_tanning";
17374
+ Contraindication2["RECENT_BOTOX"] = "recent_botox";
17375
+ Contraindication2["RECENT_FILLERS"] = "recent_fillers";
17376
+ Contraindication2["SKIN_ALLERGIES"] = "skin_allergies";
17377
+ Contraindication2["MEDICATIONS"] = "medications";
17378
+ Contraindication2["RECENT_CHEMICAL_PEEL"] = "recent_chemical_peel";
17379
+ Contraindication2["RECENT_LASER"] = "recent_laser";
17380
+ Contraindication2["SKIN_INFLAMMATION"] = "skin_inflammation";
17381
+ Contraindication2["OPEN_WOUNDS"] = "open_wounds";
17382
+ Contraindication2["HERPES_SIMPLEX"] = "herpes_simplex";
17383
+ Contraindication2["COLD_SORES"] = "cold_sores";
17384
+ return Contraindication2;
17385
+ })(Contraindication || {});
17386
+
17067
17387
  // src/backoffice/types/static/treatment-benefit.types.ts
17068
17388
  var TreatmentBenefit = /* @__PURE__ */ ((TreatmentBenefit2) => {
17069
17389
  TreatmentBenefit2["WRINKLE_REDUCTION"] = "wrinkle_reduction";