@blackcode_sa/metaestetics-api 1.8.17 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -7010,6 +7010,27 @@ var PractitionerService = class extends BaseService {
7010
7010
  } catch (error) {
7011
7011
  console.log("[PRACTITIONER_SERVICE] Strategy 3 failed:", error);
7012
7012
  }
7013
+ try {
7014
+ console.log("[PRACTITIONER_SERVICE] Strategy 4: Client-side filtering fallback");
7015
+ const constraints = [
7016
+ where10("isActive", "==", true),
7017
+ where10("status", "==", "active" /* ACTIVE */),
7018
+ orderBy4("createdAt", "desc"),
7019
+ limit7(filters.pagination || 10)
7020
+ ];
7021
+ const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
7022
+ const querySnapshot = await getDocs10(q);
7023
+ let practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
7024
+ practitioners = this.applyInMemoryFilters(practitioners, filters);
7025
+ const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
7026
+ console.log(`[PRACTITIONER_SERVICE] Strategy 4 success: ${practitioners.length} practitioners`);
7027
+ if (practitioners.length < (filters.pagination || 10)) {
7028
+ return { practitioners, lastDoc: null };
7029
+ }
7030
+ return { practitioners, lastDoc };
7031
+ } catch (error) {
7032
+ console.log("[PRACTITIONER_SERVICE] Strategy 4 failed:", error);
7033
+ }
7013
7034
  console.log("[PRACTITIONER_SERVICE] All strategies failed, returning empty result");
7014
7035
  return { practitioners: [], lastDoc: null };
7015
7036
  } catch (error) {
@@ -8321,9 +8342,7 @@ import {
8321
8342
  writeBatch as writeBatch4,
8322
8343
  arrayUnion as arrayUnion7
8323
8344
  } from "firebase/firestore";
8324
- import {
8325
- geohashForLocation as geohashForLocation4
8326
- } from "geofire-common";
8345
+ import { geohashForLocation as geohashForLocation4 } from "geofire-common";
8327
8346
  import { z as z20 } from "zod";
8328
8347
 
8329
8348
  // src/services/clinic/utils/clinic.utils.ts
@@ -8789,8 +8808,9 @@ import {
8789
8808
  limit as limit9,
8790
8809
  orderBy as orderBy5
8791
8810
  } from "firebase/firestore";
8792
- import { distanceBetween as distanceBetween4 } from "geofire-common";
8811
+ import { geohashQueryBounds as geohashQueryBounds3, distanceBetween as distanceBetween4 } from "geofire-common";
8793
8812
  async function getClinicsByFilters(db, filters) {
8813
+ var _a;
8794
8814
  try {
8795
8815
  console.log("[CLINIC_SERVICE] Starting clinic filtering with multiple strategies");
8796
8816
  if (filters.center && filters.radiusInKm) {
@@ -8805,10 +8825,53 @@ async function getClinicsByFilters(db, filters) {
8805
8825
  filters.radiusInKm = void 0;
8806
8826
  }
8807
8827
  }
8828
+ if (filters.center && filters.radiusInKm) {
8829
+ try {
8830
+ console.log("[CLINIC_SERVICE] Strategy 0: Geohash bounds prefilter");
8831
+ const bounds = geohashQueryBounds3(
8832
+ [filters.center.latitude, filters.center.longitude],
8833
+ (filters.radiusInKm || 0) * 1e3
8834
+ );
8835
+ const collected = [];
8836
+ for (const b of bounds) {
8837
+ const constraints = [
8838
+ where15("location.geohash", ">=", b[0]),
8839
+ where15("location.geohash", "<=", b[1]),
8840
+ where15("isActive", "==", (_a = filters.isActive) != null ? _a : true)
8841
+ ];
8842
+ if (filters.tags && filters.tags.length > 0) {
8843
+ constraints.push(where15("tags", "array-contains", filters.tags[0]));
8844
+ }
8845
+ const q0 = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8846
+ const snap = await getDocs15(q0);
8847
+ snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
8848
+ }
8849
+ const uniqueMap = /* @__PURE__ */ new Map();
8850
+ for (const c of collected) {
8851
+ uniqueMap.set(c.id, c);
8852
+ }
8853
+ let clinics = Array.from(uniqueMap.values());
8854
+ clinics = applyInMemoryFilters(clinics, filters);
8855
+ const pageSize = filters.pagination || 5;
8856
+ let startIndex = 0;
8857
+ if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
8858
+ const idx = clinics.findIndex((c) => c.id === filters.lastDoc.id);
8859
+ if (idx >= 0) startIndex = idx + 1;
8860
+ }
8861
+ const page = clinics.slice(startIndex, startIndex + pageSize);
8862
+ const newLastDoc = page.length === pageSize ? page[page.length - 1] : null;
8863
+ console.log(
8864
+ `[CLINIC_SERVICE] Strategy 0 success: ${page.length} clinics (of ${clinics.length})`
8865
+ );
8866
+ return { clinics: page, lastDoc: newLastDoc };
8867
+ } catch (geoErr) {
8868
+ console.log("[CLINIC_SERVICE] Strategy 0 failed:", geoErr);
8869
+ }
8870
+ }
8808
8871
  const getBaseConstraints = () => {
8809
- var _a;
8872
+ var _a2;
8810
8873
  const constraints = [];
8811
- constraints.push(where15("isActive", "==", (_a = filters.isActive) != null ? _a : true));
8874
+ constraints.push(where15("isActive", "==", (_a2 = filters.isActive) != null ? _a2 : true));
8812
8875
  if (filters.tags && filters.tags.length > 0) {
8813
8876
  constraints.push(where15("tags", "array-contains", filters.tags[0]));
8814
8877
  }
@@ -8885,7 +8948,9 @@ async function getClinicsByFilters(db, filters) {
8885
8948
  }
8886
8949
  }
8887
8950
  try {
8888
- console.log("[CLINIC_SERVICE] Strategy 3: Using createdAt ordering with client-side filtering");
8951
+ console.log(
8952
+ "[CLINIC_SERVICE] Strategy 3: Using createdAt ordering with client-side filtering"
8953
+ );
8889
8954
  const constraints = getBaseConstraints();
8890
8955
  constraints.push(orderBy5("createdAt", "desc"));
8891
8956
  if (filters.lastDoc) {
@@ -8940,20 +9005,24 @@ async function getClinicsByFilters(db, filters) {
8940
9005
  }
8941
9006
  function applyInMemoryFilters(clinics, filters) {
8942
9007
  let filteredClinics = [...clinics];
8943
- console.log(`[CLINIC_SERVICE] Applying in-memory filters - input: ${filteredClinics.length} clinics`);
9008
+ console.log(
9009
+ `[CLINIC_SERVICE] Applying in-memory filters - input: ${filteredClinics.length} clinics`
9010
+ );
8944
9011
  if (filters.tags && filters.tags.length > 1) {
8945
9012
  const initialCount = filteredClinics.length;
8946
9013
  filteredClinics = filteredClinics.filter(
8947
9014
  (clinic) => filters.tags.every((tag) => clinic.tags.includes(tag))
8948
9015
  );
8949
- console.log(`[CLINIC_SERVICE] Applied multi-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`);
9016
+ console.log(
9017
+ `[CLINIC_SERVICE] Applied multi-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`
9018
+ );
8950
9019
  }
8951
9020
  if (filters.tags && filters.tags.length === 1) {
8952
9021
  const initialCount = filteredClinics.length;
8953
- filteredClinics = filteredClinics.filter(
8954
- (clinic) => clinic.tags.includes(filters.tags[0])
9022
+ filteredClinics = filteredClinics.filter((clinic) => clinic.tags.includes(filters.tags[0]));
9023
+ console.log(
9024
+ `[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`
8955
9025
  );
8956
- console.log(`[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8957
9026
  }
8958
9027
  if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
8959
9028
  const initialCount = filteredClinics.length;
@@ -8964,7 +9033,9 @@ function applyInMemoryFilters(clinics, filters) {
8964
9033
  if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
8965
9034
  return true;
8966
9035
  });
8967
- console.log(`[CLINIC_SERVICE] Applied rating filter (${filters.minRating}-${filters.maxRating}): ${initialCount} \u2192 ${filteredClinics.length}`);
9036
+ console.log(
9037
+ `[CLINIC_SERVICE] Applied rating filter (${filters.minRating}-${filters.maxRating}): ${initialCount} \u2192 ${filteredClinics.length}`
9038
+ );
8968
9039
  }
8969
9040
  if (filters.nameSearch && filters.nameSearch.trim()) {
8970
9041
  const initialCount = filteredClinics.length;
@@ -8974,7 +9045,9 @@ function applyInMemoryFilters(clinics, filters) {
8974
9045
  const nameLower = clinic.nameLower || "";
8975
9046
  return name.includes(searchTerm) || nameLower.includes(searchTerm);
8976
9047
  });
8977
- console.log(`[CLINIC_SERVICE] Applied name search filter: ${initialCount} \u2192 ${filteredClinics.length}`);
9048
+ console.log(
9049
+ `[CLINIC_SERVICE] Applied name search filter: ${initialCount} \u2192 ${filteredClinics.length}`
9050
+ );
8978
9051
  }
8979
9052
  if (filters.procedureFamily) {
8980
9053
  const initialCount = filteredClinics.length;
@@ -8982,7 +9055,9 @@ function applyInMemoryFilters(clinics, filters) {
8982
9055
  const proceduresInfo = clinic.proceduresInfo || [];
8983
9056
  return proceduresInfo.some((proc) => proc.family === filters.procedureFamily);
8984
9057
  });
8985
- console.log(`[CLINIC_SERVICE] Applied procedure family filter: ${initialCount} \u2192 ${filteredClinics.length}`);
9058
+ console.log(
9059
+ `[CLINIC_SERVICE] Applied procedure family filter: ${initialCount} \u2192 ${filteredClinics.length}`
9060
+ );
8986
9061
  }
8987
9062
  if (filters.procedureCategory) {
8988
9063
  const initialCount = filteredClinics.length;
@@ -8990,7 +9065,9 @@ function applyInMemoryFilters(clinics, filters) {
8990
9065
  const proceduresInfo = clinic.proceduresInfo || [];
8991
9066
  return proceduresInfo.some((proc) => proc.categoryName === filters.procedureCategory);
8992
9067
  });
8993
- console.log(`[CLINIC_SERVICE] Applied procedure category filter: ${initialCount} \u2192 ${filteredClinics.length}`);
9068
+ console.log(
9069
+ `[CLINIC_SERVICE] Applied procedure category filter: ${initialCount} \u2192 ${filteredClinics.length}`
9070
+ );
8994
9071
  }
8995
9072
  if (filters.procedureSubcategory) {
8996
9073
  const initialCount = filteredClinics.length;
@@ -8998,7 +9075,9 @@ function applyInMemoryFilters(clinics, filters) {
8998
9075
  const proceduresInfo = clinic.proceduresInfo || [];
8999
9076
  return proceduresInfo.some((proc) => proc.subcategoryName === filters.procedureSubcategory);
9000
9077
  });
9001
- console.log(`[CLINIC_SERVICE] Applied procedure subcategory filter: ${initialCount} \u2192 ${filteredClinics.length}`);
9078
+ console.log(
9079
+ `[CLINIC_SERVICE] Applied procedure subcategory filter: ${initialCount} \u2192 ${filteredClinics.length}`
9080
+ );
9002
9081
  }
9003
9082
  if (filters.procedureTechnology) {
9004
9083
  const initialCount = filteredClinics.length;
@@ -9006,7 +9085,9 @@ function applyInMemoryFilters(clinics, filters) {
9006
9085
  const proceduresInfo = clinic.proceduresInfo || [];
9007
9086
  return proceduresInfo.some((proc) => proc.technologyName === filters.procedureTechnology);
9008
9087
  });
9009
- console.log(`[CLINIC_SERVICE] Applied procedure technology filter: ${initialCount} \u2192 ${filteredClinics.length}`);
9088
+ console.log(
9089
+ `[CLINIC_SERVICE] Applied procedure technology filter: ${initialCount} \u2192 ${filteredClinics.length}`
9090
+ );
9010
9091
  }
9011
9092
  if (filters.center && filters.radiusInKm) {
9012
9093
  const initialCount = filteredClinics.length;
@@ -9020,11 +9101,15 @@ function applyInMemoryFilters(clinics, filters) {
9020
9101
  [filters.center.latitude, filters.center.longitude],
9021
9102
  [clinic.location.latitude, clinic.location.longitude]
9022
9103
  ) / 1e3;
9023
- console.log(`[CLINIC_SERVICE] Clinic ${clinic.name}: distance ${distance.toFixed(2)}km (limit: ${filters.radiusInKm}km)`);
9104
+ console.log(
9105
+ `[CLINIC_SERVICE] Clinic ${clinic.name}: distance ${distance.toFixed(2)}km (limit: ${filters.radiusInKm}km)`
9106
+ );
9024
9107
  clinic.distance = distance;
9025
9108
  return distance <= filters.radiusInKm;
9026
9109
  });
9027
- console.log(`[CLINIC_SERVICE] Applied geo filter (${filters.radiusInKm}km): ${initialCount} \u2192 ${filteredClinics.length}`);
9110
+ console.log(
9111
+ `[CLINIC_SERVICE] Applied geo filter (${filters.radiusInKm}km): ${initialCount} \u2192 ${filteredClinics.length}`
9112
+ );
9028
9113
  filteredClinics.sort((a, b) => (a.distance || 0) - (b.distance || 0));
9029
9114
  }
9030
9115
  console.log(`[CLINIC_SERVICE] Final filtered result: ${filteredClinics.length} clinics`);
@@ -9052,9 +9137,7 @@ var ClinicService = class extends BaseService {
9052
9137
  return media;
9053
9138
  }
9054
9139
  if (media instanceof File || media instanceof Blob) {
9055
- console.log(
9056
- `[ClinicService] Uploading ${collectionName} media for ${ownerId}`
9057
- );
9140
+ console.log(`[ClinicService] Uploading ${collectionName} media for ${ownerId}`);
9058
9141
  const metadata = await this.mediaService.uploadMedia(
9059
9142
  media,
9060
9143
  ownerId,
@@ -9076,11 +9159,7 @@ var ClinicService = class extends BaseService {
9076
9159
  if (!mediaArray || mediaArray.length === 0) return [];
9077
9160
  const result = [];
9078
9161
  for (const media of mediaArray) {
9079
- const processedUrl = await this.processMedia(
9080
- media,
9081
- ownerId,
9082
- collectionName
9083
- );
9162
+ const processedUrl = await this.processMedia(media, ownerId, collectionName);
9084
9163
  if (processedUrl) {
9085
9164
  result.push(processedUrl);
9086
9165
  }
@@ -9098,11 +9177,7 @@ var ClinicService = class extends BaseService {
9098
9177
  if (!photosWithTags || photosWithTags.length === 0) return [];
9099
9178
  const result = [];
9100
9179
  for (const item of photosWithTags) {
9101
- const processedUrl = await this.processMedia(
9102
- item.url,
9103
- ownerId,
9104
- collectionName
9105
- );
9180
+ const processedUrl = await this.processMedia(item.url, ownerId, collectionName);
9106
9181
  if (processedUrl) {
9107
9182
  result.push({
9108
9183
  url: processedUrl,
@@ -9120,19 +9195,11 @@ var ClinicService = class extends BaseService {
9120
9195
  try {
9121
9196
  const clinicId = this.generateId();
9122
9197
  const validatedData = createClinicSchema.parse(data);
9123
- const group = await this.clinicGroupService.getClinicGroup(
9124
- validatedData.clinicGroupId
9125
- );
9198
+ const group = await this.clinicGroupService.getClinicGroup(validatedData.clinicGroupId);
9126
9199
  if (!group) {
9127
- throw new Error(
9128
- `Clinic group ${validatedData.clinicGroupId} not found`
9129
- );
9200
+ throw new Error(`Clinic group ${validatedData.clinicGroupId} not found`);
9130
9201
  }
9131
- const logoUrl = await this.processMedia(
9132
- validatedData.logo,
9133
- clinicId,
9134
- "clinic-logos"
9135
- );
9202
+ const logoUrl = await this.processMedia(validatedData.logo, clinicId, "clinic-logos");
9136
9203
  const coverPhotoUrl = await this.processMedia(
9137
9204
  validatedData.coverPhoto,
9138
9205
  clinicId,
@@ -9222,11 +9289,7 @@ var ClinicService = class extends BaseService {
9222
9289
  const validatedData = updateClinicSchema.parse(data);
9223
9290
  const updatePayload = {};
9224
9291
  if (validatedData.logo !== void 0) {
9225
- updatePayload.logo = await this.processMedia(
9226
- validatedData.logo,
9227
- clinicId,
9228
- "clinic-logos"
9229
- );
9292
+ updatePayload.logo = await this.processMedia(validatedData.logo, clinicId, "clinic-logos");
9230
9293
  }
9231
9294
  if (validatedData.coverPhoto !== void 0) {
9232
9295
  updatePayload.coverPhoto = await this.processMedia(
@@ -9326,22 +9389,10 @@ var ClinicService = class extends BaseService {
9326
9389
  * Pretražuje klinike u određenom radijusu
9327
9390
  */
9328
9391
  async findClinicsInRadius(center, radiusInKm, filters) {
9329
- return findClinicsInRadius(
9330
- this.db,
9331
- center,
9332
- radiusInKm,
9333
- filters
9334
- );
9392
+ return findClinicsInRadius(this.db, center, radiusInKm, filters);
9335
9393
  }
9336
9394
  async addTags(clinicId, adminId, newTags) {
9337
- return addTags(
9338
- this.db,
9339
- clinicId,
9340
- adminId,
9341
- newTags,
9342
- this.clinicAdminService,
9343
- this.app
9344
- );
9395
+ return addTags(this.db, clinicId, adminId, newTags, this.clinicAdminService, this.app);
9345
9396
  }
9346
9397
  async removeTags(clinicId, adminId, tagsToRemove) {
9347
9398
  return removeTags(
@@ -9379,9 +9430,7 @@ var ClinicService = class extends BaseService {
9379
9430
  clinicGroupId,
9380
9431
  adminId
9381
9432
  });
9382
- const clinicGroup = await this.clinicGroupService.getClinicGroup(
9383
- clinicGroupId
9384
- );
9433
+ const clinicGroup = await this.clinicGroupService.getClinicGroup(clinicGroupId);
9385
9434
  if (!clinicGroup) {
9386
9435
  console.error("[CLINIC_SERVICE] Clinic group not found", {
9387
9436
  clinicGroupId
@@ -9427,13 +9476,7 @@ var ClinicService = class extends BaseService {
9427
9476
  return getAllClinics(this.db, pagination, lastDoc);
9428
9477
  }
9429
9478
  async getAllClinicsInRange(center, rangeInKm, pagination, lastDoc) {
9430
- return getAllClinicsInRange(
9431
- this.db,
9432
- center,
9433
- rangeInKm,
9434
- pagination,
9435
- lastDoc
9436
- );
9479
+ return getAllClinicsInRange(this.db, center, rangeInKm, pagination, lastDoc);
9437
9480
  }
9438
9481
  /**
9439
9482
  * Get clinics based on multiple filtering criteria
@@ -14865,7 +14908,7 @@ var procedureSchema = createProcedureSchema.extend({
14865
14908
  });
14866
14909
 
14867
14910
  // src/services/procedure/procedure.service.ts
14868
- import { distanceBetween as distanceBetween6 } from "geofire-common";
14911
+ import { distanceBetween as distanceBetween6, geohashQueryBounds as geohashQueryBounds5 } from "geofire-common";
14869
14912
  var ProcedureService = class extends BaseService {
14870
14913
  constructor(db, auth, app, categoryService, subcategoryService, technologyService, productService, mediaService) {
14871
14914
  super(db, auth, app);
@@ -14888,9 +14931,7 @@ var ProcedureService = class extends BaseService {
14888
14931
  return media;
14889
14932
  }
14890
14933
  if (media instanceof File || media instanceof Blob) {
14891
- console.log(
14892
- `[ProcedureService] Uploading ${collectionName} media for ${ownerId}`
14893
- );
14934
+ console.log(`[ProcedureService] Uploading ${collectionName} media for ${ownerId}`);
14894
14935
  const metadata = await this.mediaService.uploadMedia(
14895
14936
  media,
14896
14937
  ownerId,
@@ -14912,11 +14953,7 @@ var ProcedureService = class extends BaseService {
14912
14953
  if (!mediaArray || mediaArray.length === 0) return [];
14913
14954
  const result = [];
14914
14955
  for (const media of mediaArray) {
14915
- const processedUrl = await this.processMedia(
14916
- media,
14917
- ownerId,
14918
- collectionName
14919
- );
14956
+ const processedUrl = await this.processMedia(media, ownerId, collectionName);
14920
14957
  if (processedUrl) {
14921
14958
  result.push(processedUrl);
14922
14959
  }
@@ -14934,41 +14971,23 @@ var ProcedureService = class extends BaseService {
14934
14971
  const procedureId = this.generateId();
14935
14972
  const [category, subcategory, technology, product] = await Promise.all([
14936
14973
  this.categoryService.getById(validatedData.categoryId),
14937
- this.subcategoryService.getById(
14938
- validatedData.categoryId,
14939
- validatedData.subcategoryId
14940
- ),
14974
+ this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
14941
14975
  this.technologyService.getById(validatedData.technologyId),
14942
- this.productService.getById(
14943
- validatedData.technologyId,
14944
- validatedData.productId
14945
- )
14976
+ this.productService.getById(validatedData.technologyId, validatedData.productId)
14946
14977
  ]);
14947
14978
  if (!category || !subcategory || !technology || !product) {
14948
14979
  throw new Error("One or more required base entities not found");
14949
14980
  }
14950
- const clinicRef = doc30(
14951
- this.db,
14952
- CLINICS_COLLECTION,
14953
- validatedData.clinicBranchId
14954
- );
14981
+ const clinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
14955
14982
  const clinicSnapshot = await getDoc32(clinicRef);
14956
14983
  if (!clinicSnapshot.exists()) {
14957
- throw new Error(
14958
- `Clinic with ID ${validatedData.clinicBranchId} not found`
14959
- );
14984
+ throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
14960
14985
  }
14961
14986
  const clinic = clinicSnapshot.data();
14962
- const practitionerRef = doc30(
14963
- this.db,
14964
- PRACTITIONERS_COLLECTION,
14965
- validatedData.practitionerId
14966
- );
14987
+ const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, validatedData.practitionerId);
14967
14988
  const practitionerSnapshot = await getDoc32(practitionerRef);
14968
14989
  if (!practitionerSnapshot.exists()) {
14969
- throw new Error(
14970
- `Practitioner with ID ${validatedData.practitionerId} not found`
14971
- );
14990
+ throw new Error(`Practitioner with ID ${validatedData.practitionerId} not found`);
14972
14991
  }
14973
14992
  const practitioner = practitionerSnapshot.data();
14974
14993
  let processedPhotos = [];
@@ -15057,24 +15076,16 @@ var ProcedureService = class extends BaseService {
15057
15076
  const validatedData = createProcedureSchema.parse(validationData);
15058
15077
  const [category, subcategory, technology, product, clinicSnapshot] = await Promise.all([
15059
15078
  this.categoryService.getById(validatedData.categoryId),
15060
- this.subcategoryService.getById(
15061
- validatedData.categoryId,
15062
- validatedData.subcategoryId
15063
- ),
15079
+ this.subcategoryService.getById(validatedData.categoryId, validatedData.subcategoryId),
15064
15080
  this.technologyService.getById(validatedData.technologyId),
15065
- this.productService.getById(
15066
- validatedData.technologyId,
15067
- validatedData.productId
15068
- ),
15081
+ this.productService.getById(validatedData.technologyId, validatedData.productId),
15069
15082
  getDoc32(doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId))
15070
15083
  ]);
15071
15084
  if (!category || !subcategory || !technology || !product) {
15072
15085
  throw new Error("One or more required base entities not found");
15073
15086
  }
15074
15087
  if (!clinicSnapshot.exists()) {
15075
- throw new Error(
15076
- `Clinic with ID ${validatedData.clinicBranchId} not found`
15077
- );
15088
+ throw new Error(`Clinic with ID ${validatedData.clinicBranchId} not found`);
15078
15089
  }
15079
15090
  const clinic = clinicSnapshot.data();
15080
15091
  let processedPhotos = [];
@@ -15100,12 +15111,8 @@ var ProcedureService = class extends BaseService {
15100
15111
  }
15101
15112
  if (practitionersMap.size !== practitionerIds.length) {
15102
15113
  const foundIds = Array.from(practitionersMap.keys());
15103
- const notFoundIds = practitionerIds.filter(
15104
- (id) => !foundIds.includes(id)
15105
- );
15106
- throw new Error(
15107
- `The following practitioners were not found: ${notFoundIds.join(", ")}`
15108
- );
15114
+ const notFoundIds = practitionerIds.filter((id) => !foundIds.includes(id));
15115
+ throw new Error(`The following practitioners were not found: ${notFoundIds.join(", ")}`);
15109
15116
  }
15110
15117
  const batch = writeBatch6(this.db);
15111
15118
  const createdProcedureIds = [];
@@ -15173,10 +15180,7 @@ var ProcedureService = class extends BaseService {
15173
15180
  const fetchedProcedures = [];
15174
15181
  for (let i = 0; i < createdProcedureIds.length; i += 30) {
15175
15182
  const chunk = createdProcedureIds.slice(i, i + 30);
15176
- const q = query29(
15177
- collection29(this.db, PROCEDURES_COLLECTION),
15178
- where29(documentId2(), "in", chunk)
15179
- );
15183
+ const q = query29(collection29(this.db, PROCEDURES_COLLECTION), where29(documentId2(), "in", chunk));
15180
15184
  const snapshot = await getDocs29(q);
15181
15185
  snapshot.forEach((doc37) => {
15182
15186
  fetchedProcedures.push(doc37.data());
@@ -15277,9 +15281,7 @@ var ProcedureService = class extends BaseService {
15277
15281
  );
15278
15282
  const newPractitionerSnap = await getDoc32(newPractitionerRef);
15279
15283
  if (!newPractitionerSnap.exists())
15280
- throw new Error(
15281
- `New Practitioner ${validatedData.practitionerId} not found`
15282
- );
15284
+ throw new Error(`New Practitioner ${validatedData.practitionerId} not found`);
15283
15285
  newPractitioner = newPractitionerSnap.data();
15284
15286
  updatedProcedureData.doctorInfo = {
15285
15287
  id: newPractitioner.id,
@@ -15293,11 +15295,7 @@ var ProcedureService = class extends BaseService {
15293
15295
  }
15294
15296
  if (validatedData.clinicBranchId && validatedData.clinicBranchId !== oldClinicId) {
15295
15297
  clinicChanged = true;
15296
- const newClinicRef = doc30(
15297
- this.db,
15298
- CLINICS_COLLECTION,
15299
- validatedData.clinicBranchId
15300
- );
15298
+ const newClinicRef = doc30(this.db, CLINICS_COLLECTION, validatedData.clinicBranchId);
15301
15299
  const newClinicSnap = await getDoc32(newClinicRef);
15302
15300
  if (!newClinicSnap.exists())
15303
15301
  throw new Error(`New Clinic ${validatedData.clinicBranchId} not found`);
@@ -15316,11 +15314,8 @@ var ProcedureService = class extends BaseService {
15316
15314
  updatedProcedureData.nameLower = validatedData.name.toLowerCase();
15317
15315
  }
15318
15316
  if (validatedData.categoryId) {
15319
- const category = await this.categoryService.getById(
15320
- validatedData.categoryId
15321
- );
15322
- if (!category)
15323
- throw new Error(`Category ${validatedData.categoryId} not found`);
15317
+ const category = await this.categoryService.getById(validatedData.categoryId);
15318
+ if (!category) throw new Error(`Category ${validatedData.categoryId} not found`);
15324
15319
  updatedProcedureData.category = category;
15325
15320
  finalCategoryId = category.id;
15326
15321
  }
@@ -15335,17 +15330,12 @@ var ProcedureService = class extends BaseService {
15335
15330
  );
15336
15331
  updatedProcedureData.subcategory = subcategory;
15337
15332
  } else if (validatedData.subcategoryId) {
15338
- console.warn(
15339
- "Attempted to update subcategory without a valid categoryId"
15340
- );
15333
+ console.warn("Attempted to update subcategory without a valid categoryId");
15341
15334
  }
15342
15335
  let finalTechnologyId = existingProcedure.technology.id;
15343
15336
  if (validatedData.technologyId) {
15344
- const technology = await this.technologyService.getById(
15345
- validatedData.technologyId
15346
- );
15347
- if (!technology)
15348
- throw new Error(`Technology ${validatedData.technologyId} not found`);
15337
+ const technology = await this.technologyService.getById(validatedData.technologyId);
15338
+ if (!technology) throw new Error(`Technology ${validatedData.technologyId} not found`);
15349
15339
  updatedProcedureData.technology = technology;
15350
15340
  finalTechnologyId = technology.id;
15351
15341
  updatedProcedureData.blockingConditions = technology.blockingConditions;
@@ -15356,10 +15346,7 @@ var ProcedureService = class extends BaseService {
15356
15346
  updatedProcedureData.documentationTemplates = technology.documentationTemplates || [];
15357
15347
  }
15358
15348
  if (validatedData.productId && finalTechnologyId) {
15359
- const product = await this.productService.getById(
15360
- finalTechnologyId,
15361
- validatedData.productId
15362
- );
15349
+ const product = await this.productService.getById(finalTechnologyId, validatedData.productId);
15363
15350
  if (!product)
15364
15351
  throw new Error(
15365
15352
  `Product ${validatedData.productId} not found for technology ${finalTechnologyId}`
@@ -15441,11 +15428,7 @@ var ProcedureService = class extends BaseService {
15441
15428
  limit16(pagination)
15442
15429
  );
15443
15430
  } else {
15444
- proceduresQuery = query29(
15445
- proceduresCollection,
15446
- orderBy17("name"),
15447
- limit16(pagination)
15448
- );
15431
+ proceduresQuery = query29(proceduresCollection, orderBy17("name"), limit16(pagination));
15449
15432
  }
15450
15433
  } else {
15451
15434
  proceduresQuery = query29(proceduresCollection, orderBy17("name"));
@@ -15568,7 +15551,9 @@ var ProcedureService = class extends BaseService {
15568
15551
  constraints.push(limit15(filters.pagination || 10));
15569
15552
  const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15570
15553
  const querySnapshot = await getDocs29(q);
15571
- const procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
15554
+ const procedures = querySnapshot.docs.map(
15555
+ (doc37) => ({ ...doc37.data(), id: doc37.id })
15556
+ );
15572
15557
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15573
15558
  console.log(`[PROCEDURE_SERVICE] Strategy 1 success: ${procedures.length} procedures`);
15574
15559
  if (procedures.length < (filters.pagination || 10)) {
@@ -15599,7 +15584,9 @@ var ProcedureService = class extends BaseService {
15599
15584
  constraints.push(limit15(filters.pagination || 10));
15600
15585
  const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15601
15586
  const querySnapshot = await getDocs29(q);
15602
- const procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
15587
+ const procedures = querySnapshot.docs.map(
15588
+ (doc37) => ({ ...doc37.data(), id: doc37.id })
15589
+ );
15603
15590
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15604
15591
  console.log(`[PROCEDURE_SERVICE] Strategy 2 success: ${procedures.length} procedures`);
15605
15592
  if (procedures.length < (filters.pagination || 10)) {
@@ -15611,7 +15598,9 @@ var ProcedureService = class extends BaseService {
15611
15598
  }
15612
15599
  }
15613
15600
  try {
15614
- console.log("[PROCEDURE_SERVICE] Strategy 3: Using createdAt orderBy with client-side filtering");
15601
+ console.log(
15602
+ "[PROCEDURE_SERVICE] Strategy 3: Using createdAt orderBy with client-side filtering"
15603
+ );
15615
15604
  const constraints = getBaseConstraints();
15616
15605
  constraints.push(orderBy17("createdAt", "desc"));
15617
15606
  if (filters.lastDoc) {
@@ -15626,7 +15615,9 @@ var ProcedureService = class extends BaseService {
15626
15615
  constraints.push(limit15(filters.pagination || 10));
15627
15616
  const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15628
15617
  const querySnapshot = await getDocs29(q);
15629
- let procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
15618
+ let procedures = querySnapshot.docs.map(
15619
+ (doc37) => ({ ...doc37.data(), id: doc37.id })
15620
+ );
15630
15621
  procedures = this.applyInMemoryFilters(procedures, filters);
15631
15622
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15632
15623
  console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
@@ -15646,7 +15637,9 @@ var ProcedureService = class extends BaseService {
15646
15637
  ];
15647
15638
  const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15648
15639
  const querySnapshot = await getDocs29(q);
15649
- let procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
15640
+ let procedures = querySnapshot.docs.map(
15641
+ (doc37) => ({ ...doc37.data(), id: doc37.id })
15642
+ );
15650
15643
  procedures = this.applyInMemoryFilters(procedures, filters);
15651
15644
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
15652
15645
  console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
@@ -15686,7 +15679,9 @@ var ProcedureService = class extends BaseService {
15686
15679
  if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
15687
15680
  return true;
15688
15681
  });
15689
- console.log(`[PROCEDURE_SERVICE] Applied price filter (${filters.minPrice}-${filters.maxPrice}), results: ${filteredProcedures.length}`);
15682
+ console.log(
15683
+ `[PROCEDURE_SERVICE] Applied price filter (${filters.minPrice}-${filters.maxPrice}), results: ${filteredProcedures.length}`
15684
+ );
15690
15685
  }
15691
15686
  if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
15692
15687
  filteredProcedures = filteredProcedures.filter((procedure) => {
@@ -15696,7 +15691,9 @@ var ProcedureService = class extends BaseService {
15696
15691
  if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
15697
15692
  return true;
15698
15693
  });
15699
- console.log(`[PROCEDURE_SERVICE] Applied rating filter, results: ${filteredProcedures.length}`);
15694
+ console.log(
15695
+ `[PROCEDURE_SERVICE] Applied rating filter, results: ${filteredProcedures.length}`
15696
+ );
15700
15697
  }
15701
15698
  if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
15702
15699
  const benefitsToMatch = filters.treatmentBenefits;
@@ -15704,32 +15701,50 @@ var ProcedureService = class extends BaseService {
15704
15701
  const procedureBenefits = procedure.treatmentBenefits || [];
15705
15702
  return benefitsToMatch.some((benefit) => procedureBenefits.includes(benefit));
15706
15703
  });
15707
- console.log(`[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`);
15704
+ console.log(
15705
+ `[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`
15706
+ );
15708
15707
  }
15709
15708
  if (filters.procedureFamily) {
15710
- filteredProcedures = filteredProcedures.filter((procedure) => procedure.family === filters.procedureFamily);
15711
- console.log(`[PROCEDURE_SERVICE] Applied family filter, results: ${filteredProcedures.length}`);
15709
+ filteredProcedures = filteredProcedures.filter(
15710
+ (procedure) => procedure.family === filters.procedureFamily
15711
+ );
15712
+ console.log(
15713
+ `[PROCEDURE_SERVICE] Applied family filter, results: ${filteredProcedures.length}`
15714
+ );
15712
15715
  }
15713
15716
  if (filters.procedureCategory) {
15714
- filteredProcedures = filteredProcedures.filter((procedure) => {
15715
- var _a;
15716
- return ((_a = procedure.category) == null ? void 0 : _a.id) === filters.procedureCategory;
15717
- });
15718
- console.log(`[PROCEDURE_SERVICE] Applied category filter, results: ${filteredProcedures.length}`);
15717
+ filteredProcedures = filteredProcedures.filter(
15718
+ (procedure) => {
15719
+ var _a;
15720
+ return ((_a = procedure.category) == null ? void 0 : _a.id) === filters.procedureCategory;
15721
+ }
15722
+ );
15723
+ console.log(
15724
+ `[PROCEDURE_SERVICE] Applied category filter, results: ${filteredProcedures.length}`
15725
+ );
15719
15726
  }
15720
15727
  if (filters.procedureSubcategory) {
15721
- filteredProcedures = filteredProcedures.filter((procedure) => {
15722
- var _a;
15723
- return ((_a = procedure.subcategory) == null ? void 0 : _a.id) === filters.procedureSubcategory;
15724
- });
15725
- console.log(`[PROCEDURE_SERVICE] Applied subcategory filter, results: ${filteredProcedures.length}`);
15728
+ filteredProcedures = filteredProcedures.filter(
15729
+ (procedure) => {
15730
+ var _a;
15731
+ return ((_a = procedure.subcategory) == null ? void 0 : _a.id) === filters.procedureSubcategory;
15732
+ }
15733
+ );
15734
+ console.log(
15735
+ `[PROCEDURE_SERVICE] Applied subcategory filter, results: ${filteredProcedures.length}`
15736
+ );
15726
15737
  }
15727
15738
  if (filters.procedureTechnology) {
15728
- filteredProcedures = filteredProcedures.filter((procedure) => {
15729
- var _a;
15730
- return ((_a = procedure.technology) == null ? void 0 : _a.id) === filters.procedureTechnology;
15731
- });
15732
- console.log(`[PROCEDURE_SERVICE] Applied technology filter, results: ${filteredProcedures.length}`);
15739
+ filteredProcedures = filteredProcedures.filter(
15740
+ (procedure) => {
15741
+ var _a;
15742
+ return ((_a = procedure.technology) == null ? void 0 : _a.id) === filters.procedureTechnology;
15743
+ }
15744
+ );
15745
+ console.log(
15746
+ `[PROCEDURE_SERVICE] Applied technology filter, results: ${filteredProcedures.length}`
15747
+ );
15733
15748
  }
15734
15749
  if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
15735
15750
  const location = filters.location;
@@ -15753,29 +15768,48 @@ var ProcedureService = class extends BaseService {
15753
15768
  return filteredProcedures;
15754
15769
  }
15755
15770
  handleGeoQuery(filters) {
15756
- console.log("[PROCEDURE_SERVICE] Executing geo query with enhanced debugging");
15771
+ console.log("[PROCEDURE_SERVICE] Executing geo query with geohash bounds");
15757
15772
  try {
15758
15773
  const location = filters.location;
15759
15774
  const radiusInKm = filters.radiusInKm;
15760
- console.log("[PROCEDURE_SERVICE] Geo query parameters:", {
15761
- latitude: location.latitude,
15762
- longitude: location.longitude,
15763
- radiusInKm,
15764
- pagination: filters.pagination || 10
15775
+ if (!location || !radiusInKm) {
15776
+ return Promise.resolve({ procedures: [], lastDoc: null });
15777
+ }
15778
+ const bounds = geohashQueryBounds5([location.latitude, location.longitude], radiusInKm * 1e3);
15779
+ const fetches = bounds.map((b) => {
15780
+ const constraints = [
15781
+ where29("clinicInfo.location.geohash", ">=", b[0]),
15782
+ where29("clinicInfo.location.geohash", "<=", b[1]),
15783
+ where29("isActive", "==", filters.isActive !== void 0 ? filters.isActive : true)
15784
+ ];
15785
+ return getDocs29(query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints));
15765
15786
  });
15766
- const constraints = [
15767
- where29("isActive", "==", true),
15768
- orderBy17("createdAt", "desc"),
15769
- limit15((filters.pagination || 10) * 3)
15770
- // Get more results for geo filtering
15771
- ];
15772
- const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
15773
- return getDocs29(q).then((querySnapshot) => {
15774
- let procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
15787
+ return Promise.all(fetches).then((snaps) => {
15788
+ const collected = [];
15789
+ snaps.forEach((snap) => {
15790
+ snap.docs.forEach((d) => collected.push({ ...d.data(), id: d.id }));
15791
+ });
15792
+ const uniqueMap = /* @__PURE__ */ new Map();
15793
+ for (const p of collected) {
15794
+ uniqueMap.set(p.id, p);
15795
+ }
15796
+ let procedures = Array.from(uniqueMap.values());
15775
15797
  procedures = this.applyInMemoryFilters(procedures, filters);
15776
- console.log(`[PROCEDURE_SERVICE] Geo query success: ${procedures.length} procedures within ${radiusInKm}km`);
15777
- const lastDoc = procedures.length < (filters.pagination || 10) ? null : querySnapshot.docs[querySnapshot.docs.length - 1];
15778
- return { procedures, lastDoc };
15798
+ const pageSize = filters.pagination || 10;
15799
+ let startIndex = 0;
15800
+ if (filters.lastDoc && typeof filters.lastDoc === "object" && filters.lastDoc.id) {
15801
+ const idx = procedures.findIndex((p) => p.id === filters.lastDoc.id);
15802
+ if (idx >= 0) startIndex = idx + 1;
15803
+ }
15804
+ const page = procedures.slice(startIndex, startIndex + pageSize);
15805
+ const newLastDoc = page.length === pageSize ? page[page.length - 1] : null;
15806
+ console.log(
15807
+ `[PROCEDURE_SERVICE] Geo query success: ${page.length} (of ${procedures.length}) within ${radiusInKm}km`
15808
+ );
15809
+ return { procedures: page, lastDoc: newLastDoc };
15810
+ }).catch((err) => {
15811
+ console.error("[PROCEDURE_SERVICE] Geo bounds fetch failed:", err);
15812
+ return { procedures: [], lastDoc: null };
15779
15813
  });
15780
15814
  } catch (error) {
15781
15815
  console.error("[PROCEDURE_SERVICE] Geo query failed:", error);
@@ -15805,11 +15839,7 @@ var ProcedureService = class extends BaseService {
15805
15839
  throw new Error(`Clinic with ID ${data.clinicBranchId} not found`);
15806
15840
  }
15807
15841
  const clinic = clinicSnapshot.data();
15808
- const practitionerRef = doc30(
15809
- this.db,
15810
- PRACTITIONERS_COLLECTION,
15811
- data.practitionerId
15812
- );
15842
+ const practitionerRef = doc30(this.db, PRACTITIONERS_COLLECTION, data.practitionerId);
15813
15843
  const practitionerSnapshot = await getDoc32(practitionerRef);
15814
15844
  if (!practitionerSnapshot.exists()) {
15815
15845
  throw new Error(`Practitioner with ID ${data.practitionerId} not found`);
@@ -15817,11 +15847,7 @@ var ProcedureService = class extends BaseService {
15817
15847
  const practitioner = practitionerSnapshot.data();
15818
15848
  let processedPhotos = [];
15819
15849
  if (data.photos && data.photos.length > 0) {
15820
- processedPhotos = await this.processMediaArray(
15821
- data.photos,
15822
- procedureId,
15823
- "procedure-photos"
15824
- );
15850
+ processedPhotos = await this.processMediaArray(data.photos, procedureId, "procedure-photos");
15825
15851
  }
15826
15852
  const clinicInfo = {
15827
15853
  id: clinicSnapshot.id,