@blackcode_sa/metaestetics-api 1.8.16 → 1.8.17

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.js CHANGED
@@ -8710,15 +8710,6 @@ async function getClinicsByFilters(db, filters) {
8710
8710
  if (filters.tags && filters.tags.length > 0) {
8711
8711
  constraints.push((0, import_firestore26.where)("tags", "array-contains", filters.tags[0]));
8712
8712
  }
8713
- if (filters.procedureTechnology) {
8714
- constraints.push((0, import_firestore26.where)("servicesInfo.technology", "==", filters.procedureTechnology));
8715
- } else if (filters.procedureSubcategory) {
8716
- constraints.push((0, import_firestore26.where)("servicesInfo.subCategory", "==", filters.procedureSubcategory));
8717
- } else if (filters.procedureCategory) {
8718
- constraints.push((0, import_firestore26.where)("servicesInfo.category", "==", filters.procedureCategory));
8719
- } else if (filters.procedureFamily) {
8720
- constraints.push((0, import_firestore26.where)("servicesInfo.procedureFamily", "==", filters.procedureFamily));
8721
- }
8722
8713
  if (filters.minRating !== void 0) {
8723
8714
  constraints.push((0, import_firestore26.where)("reviewInfo.averageRating", ">=", filters.minRating));
8724
8715
  }
@@ -8808,15 +8799,6 @@ async function getClinicsByFilters(db, filters) {
8808
8799
  const q = (0, import_firestore26.query)((0, import_firestore26.collection)(db, CLINICS_COLLECTION), ...constraints);
8809
8800
  const querySnapshot = await (0, import_firestore26.getDocs)(q);
8810
8801
  let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8811
- if (filters.nameSearch && filters.nameSearch.trim()) {
8812
- const searchTerm = filters.nameSearch.trim().toLowerCase();
8813
- clinics = clinics.filter((clinic) => {
8814
- const name = (clinic.name || "").toLowerCase();
8815
- const nameLower = clinic.nameLower || "";
8816
- return name.includes(searchTerm) || nameLower.includes(searchTerm);
8817
- });
8818
- console.log(`[CLINIC_SERVICE] Applied name filter, results: ${clinics.length}`);
8819
- }
8820
8802
  clinics = applyInMemoryFilters(clinics, filters);
8821
8803
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8822
8804
  console.log(`[CLINIC_SERVICE] Strategy 3 success: ${clinics.length} clinics`);
@@ -8837,15 +8819,6 @@ async function getClinicsByFilters(db, filters) {
8837
8819
  const q = (0, import_firestore26.query)((0, import_firestore26.collection)(db, CLINICS_COLLECTION), ...constraints);
8838
8820
  const querySnapshot = await (0, import_firestore26.getDocs)(q);
8839
8821
  let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8840
- if (filters.nameSearch && filters.nameSearch.trim()) {
8841
- const searchTerm = filters.nameSearch.trim().toLowerCase();
8842
- clinics = clinics.filter((clinic) => {
8843
- const name = (clinic.name || "").toLowerCase();
8844
- const nameLower = clinic.nameLower || "";
8845
- return name.includes(searchTerm) || nameLower.includes(searchTerm);
8846
- });
8847
- console.log(`[CLINIC_SERVICE] Applied name filter, results: ${clinics.length}`);
8848
- }
8849
8822
  clinics = applyInMemoryFilters(clinics, filters);
8850
8823
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8851
8824
  console.log(`[CLINIC_SERVICE] Strategy 4 success: ${clinics.length} clinics`);
@@ -8864,21 +8837,96 @@ async function getClinicsByFilters(db, filters) {
8864
8837
  }
8865
8838
  }
8866
8839
  function applyInMemoryFilters(clinics, filters) {
8840
+ let filteredClinics = [...clinics];
8841
+ console.log(`[CLINIC_SERVICE] Applying in-memory filters - input: ${filteredClinics.length} clinics`);
8867
8842
  if (filters.tags && filters.tags.length > 1) {
8868
- clinics = clinics.filter((clinic) => filters.tags.every((tag) => clinic.tags.includes(tag)));
8843
+ const initialCount = filteredClinics.length;
8844
+ filteredClinics = filteredClinics.filter(
8845
+ (clinic) => filters.tags.every((tag) => clinic.tags.includes(tag))
8846
+ );
8847
+ console.log(`[CLINIC_SERVICE] Applied multi-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8848
+ }
8849
+ if (filters.tags && filters.tags.length === 1) {
8850
+ const initialCount = filteredClinics.length;
8851
+ filteredClinics = filteredClinics.filter(
8852
+ (clinic) => clinic.tags.includes(filters.tags[0])
8853
+ );
8854
+ console.log(`[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8855
+ }
8856
+ if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
8857
+ const initialCount = filteredClinics.length;
8858
+ filteredClinics = filteredClinics.filter((clinic) => {
8859
+ var _a;
8860
+ const rating = ((_a = clinic.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
8861
+ if (filters.minRating !== void 0 && rating < filters.minRating) return false;
8862
+ if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
8863
+ return true;
8864
+ });
8865
+ console.log(`[CLINIC_SERVICE] Applied rating filter (${filters.minRating}-${filters.maxRating}): ${initialCount} \u2192 ${filteredClinics.length}`);
8866
+ }
8867
+ if (filters.nameSearch && filters.nameSearch.trim()) {
8868
+ const initialCount = filteredClinics.length;
8869
+ const searchTerm = filters.nameSearch.trim().toLowerCase();
8870
+ filteredClinics = filteredClinics.filter((clinic) => {
8871
+ const name = (clinic.name || "").toLowerCase();
8872
+ const nameLower = clinic.nameLower || "";
8873
+ return name.includes(searchTerm) || nameLower.includes(searchTerm);
8874
+ });
8875
+ console.log(`[CLINIC_SERVICE] Applied name search filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8876
+ }
8877
+ if (filters.procedureFamily) {
8878
+ const initialCount = filteredClinics.length;
8879
+ filteredClinics = filteredClinics.filter((clinic) => {
8880
+ const proceduresInfo = clinic.proceduresInfo || [];
8881
+ return proceduresInfo.some((proc) => proc.family === filters.procedureFamily);
8882
+ });
8883
+ console.log(`[CLINIC_SERVICE] Applied procedure family filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8884
+ }
8885
+ if (filters.procedureCategory) {
8886
+ const initialCount = filteredClinics.length;
8887
+ filteredClinics = filteredClinics.filter((clinic) => {
8888
+ const proceduresInfo = clinic.proceduresInfo || [];
8889
+ return proceduresInfo.some((proc) => proc.categoryName === filters.procedureCategory);
8890
+ });
8891
+ console.log(`[CLINIC_SERVICE] Applied procedure category filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8892
+ }
8893
+ if (filters.procedureSubcategory) {
8894
+ const initialCount = filteredClinics.length;
8895
+ filteredClinics = filteredClinics.filter((clinic) => {
8896
+ const proceduresInfo = clinic.proceduresInfo || [];
8897
+ return proceduresInfo.some((proc) => proc.subcategoryName === filters.procedureSubcategory);
8898
+ });
8899
+ console.log(`[CLINIC_SERVICE] Applied procedure subcategory filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8900
+ }
8901
+ if (filters.procedureTechnology) {
8902
+ const initialCount = filteredClinics.length;
8903
+ filteredClinics = filteredClinics.filter((clinic) => {
8904
+ const proceduresInfo = clinic.proceduresInfo || [];
8905
+ return proceduresInfo.some((proc) => proc.technologyName === filters.procedureTechnology);
8906
+ });
8907
+ console.log(`[CLINIC_SERVICE] Applied procedure technology filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8869
8908
  }
8870
8909
  if (filters.center && filters.radiusInKm) {
8871
- clinics = clinics.filter((clinic) => {
8910
+ const initialCount = filteredClinics.length;
8911
+ filteredClinics = filteredClinics.filter((clinic) => {
8912
+ var _a, _b;
8913
+ if (!((_a = clinic.location) == null ? void 0 : _a.latitude) || !((_b = clinic.location) == null ? void 0 : _b.longitude)) {
8914
+ console.log(`[CLINIC_SERVICE] Clinic ${clinic.id} missing location data`);
8915
+ return false;
8916
+ }
8872
8917
  const distance = (0, import_geofire_common6.distanceBetween)(
8873
8918
  [filters.center.latitude, filters.center.longitude],
8874
8919
  [clinic.location.latitude, clinic.location.longitude]
8875
8920
  ) / 1e3;
8921
+ console.log(`[CLINIC_SERVICE] Clinic ${clinic.name}: distance ${distance.toFixed(2)}km (limit: ${filters.radiusInKm}km)`);
8876
8922
  clinic.distance = distance;
8877
8923
  return distance <= filters.radiusInKm;
8878
8924
  });
8879
- clinics.sort((a, b) => (a.distance || 0) - (b.distance || 0));
8925
+ console.log(`[CLINIC_SERVICE] Applied geo filter (${filters.radiusInKm}km): ${initialCount} \u2192 ${filteredClinics.length}`);
8926
+ filteredClinics.sort((a, b) => (a.distance || 0) - (b.distance || 0));
8880
8927
  }
8881
- return clinics;
8928
+ console.log(`[CLINIC_SERVICE] Final filtered result: ${filteredClinics.length} clinics`);
8929
+ return filteredClinics;
8882
8930
  }
8883
8931
 
8884
8932
  // src/services/clinic/clinic.service.ts
package/dist/index.mjs CHANGED
@@ -8812,15 +8812,6 @@ async function getClinicsByFilters(db, filters) {
8812
8812
  if (filters.tags && filters.tags.length > 0) {
8813
8813
  constraints.push(where15("tags", "array-contains", filters.tags[0]));
8814
8814
  }
8815
- if (filters.procedureTechnology) {
8816
- constraints.push(where15("servicesInfo.technology", "==", filters.procedureTechnology));
8817
- } else if (filters.procedureSubcategory) {
8818
- constraints.push(where15("servicesInfo.subCategory", "==", filters.procedureSubcategory));
8819
- } else if (filters.procedureCategory) {
8820
- constraints.push(where15("servicesInfo.category", "==", filters.procedureCategory));
8821
- } else if (filters.procedureFamily) {
8822
- constraints.push(where15("servicesInfo.procedureFamily", "==", filters.procedureFamily));
8823
- }
8824
8815
  if (filters.minRating !== void 0) {
8825
8816
  constraints.push(where15("reviewInfo.averageRating", ">=", filters.minRating));
8826
8817
  }
@@ -8910,15 +8901,6 @@ async function getClinicsByFilters(db, filters) {
8910
8901
  const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8911
8902
  const querySnapshot = await getDocs15(q);
8912
8903
  let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8913
- if (filters.nameSearch && filters.nameSearch.trim()) {
8914
- const searchTerm = filters.nameSearch.trim().toLowerCase();
8915
- clinics = clinics.filter((clinic) => {
8916
- const name = (clinic.name || "").toLowerCase();
8917
- const nameLower = clinic.nameLower || "";
8918
- return name.includes(searchTerm) || nameLower.includes(searchTerm);
8919
- });
8920
- console.log(`[CLINIC_SERVICE] Applied name filter, results: ${clinics.length}`);
8921
- }
8922
8904
  clinics = applyInMemoryFilters(clinics, filters);
8923
8905
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8924
8906
  console.log(`[CLINIC_SERVICE] Strategy 3 success: ${clinics.length} clinics`);
@@ -8939,15 +8921,6 @@ async function getClinicsByFilters(db, filters) {
8939
8921
  const q = query15(collection15(db, CLINICS_COLLECTION), ...constraints);
8940
8922
  const querySnapshot = await getDocs15(q);
8941
8923
  let clinics = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
8942
- if (filters.nameSearch && filters.nameSearch.trim()) {
8943
- const searchTerm = filters.nameSearch.trim().toLowerCase();
8944
- clinics = clinics.filter((clinic) => {
8945
- const name = (clinic.name || "").toLowerCase();
8946
- const nameLower = clinic.nameLower || "";
8947
- return name.includes(searchTerm) || nameLower.includes(searchTerm);
8948
- });
8949
- console.log(`[CLINIC_SERVICE] Applied name filter, results: ${clinics.length}`);
8950
- }
8951
8924
  clinics = applyInMemoryFilters(clinics, filters);
8952
8925
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
8953
8926
  console.log(`[CLINIC_SERVICE] Strategy 4 success: ${clinics.length} clinics`);
@@ -8966,21 +8939,96 @@ async function getClinicsByFilters(db, filters) {
8966
8939
  }
8967
8940
  }
8968
8941
  function applyInMemoryFilters(clinics, filters) {
8942
+ let filteredClinics = [...clinics];
8943
+ console.log(`[CLINIC_SERVICE] Applying in-memory filters - input: ${filteredClinics.length} clinics`);
8969
8944
  if (filters.tags && filters.tags.length > 1) {
8970
- clinics = clinics.filter((clinic) => filters.tags.every((tag) => clinic.tags.includes(tag)));
8945
+ const initialCount = filteredClinics.length;
8946
+ filteredClinics = filteredClinics.filter(
8947
+ (clinic) => filters.tags.every((tag) => clinic.tags.includes(tag))
8948
+ );
8949
+ console.log(`[CLINIC_SERVICE] Applied multi-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8950
+ }
8951
+ if (filters.tags && filters.tags.length === 1) {
8952
+ const initialCount = filteredClinics.length;
8953
+ filteredClinics = filteredClinics.filter(
8954
+ (clinic) => clinic.tags.includes(filters.tags[0])
8955
+ );
8956
+ console.log(`[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8957
+ }
8958
+ if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
8959
+ const initialCount = filteredClinics.length;
8960
+ filteredClinics = filteredClinics.filter((clinic) => {
8961
+ var _a;
8962
+ const rating = ((_a = clinic.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
8963
+ if (filters.minRating !== void 0 && rating < filters.minRating) return false;
8964
+ if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
8965
+ return true;
8966
+ });
8967
+ console.log(`[CLINIC_SERVICE] Applied rating filter (${filters.minRating}-${filters.maxRating}): ${initialCount} \u2192 ${filteredClinics.length}`);
8968
+ }
8969
+ if (filters.nameSearch && filters.nameSearch.trim()) {
8970
+ const initialCount = filteredClinics.length;
8971
+ const searchTerm = filters.nameSearch.trim().toLowerCase();
8972
+ filteredClinics = filteredClinics.filter((clinic) => {
8973
+ const name = (clinic.name || "").toLowerCase();
8974
+ const nameLower = clinic.nameLower || "";
8975
+ return name.includes(searchTerm) || nameLower.includes(searchTerm);
8976
+ });
8977
+ console.log(`[CLINIC_SERVICE] Applied name search filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8978
+ }
8979
+ if (filters.procedureFamily) {
8980
+ const initialCount = filteredClinics.length;
8981
+ filteredClinics = filteredClinics.filter((clinic) => {
8982
+ const proceduresInfo = clinic.proceduresInfo || [];
8983
+ return proceduresInfo.some((proc) => proc.family === filters.procedureFamily);
8984
+ });
8985
+ console.log(`[CLINIC_SERVICE] Applied procedure family filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8986
+ }
8987
+ if (filters.procedureCategory) {
8988
+ const initialCount = filteredClinics.length;
8989
+ filteredClinics = filteredClinics.filter((clinic) => {
8990
+ const proceduresInfo = clinic.proceduresInfo || [];
8991
+ return proceduresInfo.some((proc) => proc.categoryName === filters.procedureCategory);
8992
+ });
8993
+ console.log(`[CLINIC_SERVICE] Applied procedure category filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8994
+ }
8995
+ if (filters.procedureSubcategory) {
8996
+ const initialCount = filteredClinics.length;
8997
+ filteredClinics = filteredClinics.filter((clinic) => {
8998
+ const proceduresInfo = clinic.proceduresInfo || [];
8999
+ return proceduresInfo.some((proc) => proc.subcategoryName === filters.procedureSubcategory);
9000
+ });
9001
+ console.log(`[CLINIC_SERVICE] Applied procedure subcategory filter: ${initialCount} \u2192 ${filteredClinics.length}`);
9002
+ }
9003
+ if (filters.procedureTechnology) {
9004
+ const initialCount = filteredClinics.length;
9005
+ filteredClinics = filteredClinics.filter((clinic) => {
9006
+ const proceduresInfo = clinic.proceduresInfo || [];
9007
+ return proceduresInfo.some((proc) => proc.technologyName === filters.procedureTechnology);
9008
+ });
9009
+ console.log(`[CLINIC_SERVICE] Applied procedure technology filter: ${initialCount} \u2192 ${filteredClinics.length}`);
8971
9010
  }
8972
9011
  if (filters.center && filters.radiusInKm) {
8973
- clinics = clinics.filter((clinic) => {
9012
+ const initialCount = filteredClinics.length;
9013
+ filteredClinics = filteredClinics.filter((clinic) => {
9014
+ var _a, _b;
9015
+ if (!((_a = clinic.location) == null ? void 0 : _a.latitude) || !((_b = clinic.location) == null ? void 0 : _b.longitude)) {
9016
+ console.log(`[CLINIC_SERVICE] Clinic ${clinic.id} missing location data`);
9017
+ return false;
9018
+ }
8974
9019
  const distance = distanceBetween4(
8975
9020
  [filters.center.latitude, filters.center.longitude],
8976
9021
  [clinic.location.latitude, clinic.location.longitude]
8977
9022
  ) / 1e3;
9023
+ console.log(`[CLINIC_SERVICE] Clinic ${clinic.name}: distance ${distance.toFixed(2)}km (limit: ${filters.radiusInKm}km)`);
8978
9024
  clinic.distance = distance;
8979
9025
  return distance <= filters.radiusInKm;
8980
9026
  });
8981
- clinics.sort((a, b) => (a.distance || 0) - (b.distance || 0));
9027
+ console.log(`[CLINIC_SERVICE] Applied geo filter (${filters.radiusInKm}km): ${initialCount} \u2192 ${filteredClinics.length}`);
9028
+ filteredClinics.sort((a, b) => (a.distance || 0) - (b.distance || 0));
8982
9029
  }
8983
- return clinics;
9030
+ console.log(`[CLINIC_SERVICE] Final filtered result: ${filteredClinics.length} clinics`);
9031
+ return filteredClinics;
8984
9032
  }
8985
9033
 
8986
9034
  // src/services/clinic/clinic.service.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@blackcode_sa/metaestetics-api",
3
3
  "private": false,
4
- "version": "1.8.16",
4
+ "version": "1.8.17",
5
5
  "description": "Firebase authentication service with anonymous upgrade support",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -70,17 +70,6 @@ export async function getClinicsByFilters(
70
70
  constraints.push(where("tags", "array-contains", filters.tags[0]));
71
71
  }
72
72
 
73
- // Procedure filters (most specific first)
74
- if (filters.procedureTechnology) {
75
- constraints.push(where("servicesInfo.technology", "==", filters.procedureTechnology));
76
- } else if (filters.procedureSubcategory) {
77
- constraints.push(where("servicesInfo.subCategory", "==", filters.procedureSubcategory));
78
- } else if (filters.procedureCategory) {
79
- constraints.push(where("servicesInfo.category", "==", filters.procedureCategory));
80
- } else if (filters.procedureFamily) {
81
- constraints.push(where("servicesInfo.procedureFamily", "==", filters.procedureFamily));
82
- }
83
-
84
73
  // Rating filters
85
74
  if (filters.minRating !== undefined) {
86
75
  constraints.push(where("reviewInfo.averageRating", ">=", filters.minRating));
@@ -197,18 +186,7 @@ export async function getClinicsByFilters(
197
186
  const querySnapshot = await getDocs(q);
198
187
  let clinics = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as Clinic));
199
188
 
200
- // Client-side name filtering
201
- if (filters.nameSearch && filters.nameSearch.trim()) {
202
- const searchTerm = filters.nameSearch.trim().toLowerCase();
203
- clinics = clinics.filter(clinic => {
204
- const name = (clinic.name || '').toLowerCase();
205
- const nameLower = clinic.nameLower || '';
206
- return name.includes(searchTerm) || nameLower.includes(searchTerm);
207
- });
208
- console.log(`[CLINIC_SERVICE] Applied name filter, results: ${clinics.length}`);
209
- }
210
-
211
- // Apply in-memory filters
189
+ // Apply in-memory filters (includes name search)
212
190
  clinics = applyInMemoryFilters(clinics, filters);
213
191
 
214
192
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
@@ -237,18 +215,7 @@ export async function getClinicsByFilters(
237
215
  const querySnapshot = await getDocs(q);
238
216
  let clinics = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as Clinic));
239
217
 
240
- // Client-side name filtering
241
- if (filters.nameSearch && filters.nameSearch.trim()) {
242
- const searchTerm = filters.nameSearch.trim().toLowerCase();
243
- clinics = clinics.filter(clinic => {
244
- const name = (clinic.name || '').toLowerCase();
245
- const nameLower = clinic.nameLower || '';
246
- return name.includes(searchTerm) || nameLower.includes(searchTerm);
247
- });
248
- console.log(`[CLINIC_SERVICE] Applied name filter, results: ${clinics.length}`);
249
- }
250
-
251
- // Apply in-memory filters
218
+ // Apply in-memory filters (includes name search)
252
219
  clinics = applyInMemoryFilters(clinics, filters);
253
220
 
254
221
  const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
@@ -278,27 +245,118 @@ export async function getClinicsByFilters(
278
245
  * Helper function to apply in-memory filters that Firestore doesn't support well
279
246
  */
280
247
  function applyInMemoryFilters(clinics: Clinic[], filters: any): (Clinic & { distance?: number })[] {
281
- // Multi-tag filter (Firestore only supports single array-contains)
248
+ let filteredClinics = [...clinics]; // Kreiraj kopiju
249
+
250
+ console.log(`[CLINIC_SERVICE] Applying in-memory filters - input: ${filteredClinics.length} clinics`);
251
+
252
+ // ✅ Multi-tag filter (postojeći kod)
282
253
  if (filters.tags && filters.tags.length > 1) {
283
- clinics = clinics.filter(clinic => filters.tags!.every((tag: ClinicTag) => clinic.tags.includes(tag)));
254
+ const initialCount = filteredClinics.length;
255
+ filteredClinics = filteredClinics.filter(clinic =>
256
+ filters.tags.every((tag: ClinicTag) => clinic.tags.includes(tag))
257
+ );
258
+ console.log(`[CLINIC_SERVICE] Applied multi-tag filter: ${initialCount} → ${filteredClinics.length}`);
284
259
  }
285
-
286
- // Geo-radius filter
260
+
261
+ // 🆕 DODAJTE: Single tag filter (za Strategy 4 fallback)
262
+ if (filters.tags && filters.tags.length === 1) {
263
+ const initialCount = filteredClinics.length;
264
+ filteredClinics = filteredClinics.filter(clinic =>
265
+ clinic.tags.includes(filters.tags[0])
266
+ );
267
+ console.log(`[CLINIC_SERVICE] Applied single-tag filter: ${initialCount} → ${filteredClinics.length}`);
268
+ }
269
+
270
+ // 🆕 DODAJTE: Rating filter
271
+ if (filters.minRating !== undefined || filters.maxRating !== undefined) {
272
+ const initialCount = filteredClinics.length;
273
+ filteredClinics = filteredClinics.filter(clinic => {
274
+ const rating = clinic.reviewInfo?.averageRating || 0;
275
+ if (filters.minRating !== undefined && rating < filters.minRating) return false;
276
+ if (filters.maxRating !== undefined && rating > filters.maxRating) return false;
277
+ return true;
278
+ });
279
+ console.log(`[CLINIC_SERVICE] Applied rating filter (${filters.minRating}-${filters.maxRating}): ${initialCount} → ${filteredClinics.length}`);
280
+ }
281
+
282
+ // 🆕 DODAJTE: Name search filter
283
+ if (filters.nameSearch && filters.nameSearch.trim()) {
284
+ const initialCount = filteredClinics.length;
285
+ const searchTerm = filters.nameSearch.trim().toLowerCase();
286
+ filteredClinics = filteredClinics.filter(clinic => {
287
+ const name = (clinic.name || '').toLowerCase();
288
+ const nameLower = clinic.nameLower || '';
289
+ return name.includes(searchTerm) || nameLower.includes(searchTerm);
290
+ });
291
+ console.log(`[CLINIC_SERVICE] Applied name search filter: ${initialCount} → ${filteredClinics.length}`);
292
+ }
293
+
294
+ // 🆕 DODAJTE: Procedure family filtering
295
+ if (filters.procedureFamily) {
296
+ const initialCount = filteredClinics.length;
297
+ filteredClinics = filteredClinics.filter(clinic => {
298
+ const proceduresInfo = clinic.proceduresInfo || [];
299
+ return proceduresInfo.some(proc => proc.family === filters.procedureFamily);
300
+ });
301
+ console.log(`[CLINIC_SERVICE] Applied procedure family filter: ${initialCount} → ${filteredClinics.length}`);
302
+ }
303
+
304
+ // 🆕 DODAJTE: Procedure category filtering
305
+ if (filters.procedureCategory) {
306
+ const initialCount = filteredClinics.length;
307
+ filteredClinics = filteredClinics.filter(clinic => {
308
+ const proceduresInfo = clinic.proceduresInfo || [];
309
+ return proceduresInfo.some(proc => proc.categoryName === filters.procedureCategory);
310
+ });
311
+ console.log(`[CLINIC_SERVICE] Applied procedure category filter: ${initialCount} → ${filteredClinics.length}`);
312
+ }
313
+
314
+ // 🆕 DODAJTE: Procedure subcategory filtering
315
+ if (filters.procedureSubcategory) {
316
+ const initialCount = filteredClinics.length;
317
+ filteredClinics = filteredClinics.filter(clinic => {
318
+ const proceduresInfo = clinic.proceduresInfo || [];
319
+ return proceduresInfo.some(proc => proc.subcategoryName === filters.procedureSubcategory);
320
+ });
321
+ console.log(`[CLINIC_SERVICE] Applied procedure subcategory filter: ${initialCount} → ${filteredClinics.length}`);
322
+ }
323
+
324
+ // 🆕 DODAJTE: Procedure technology filtering
325
+ if (filters.procedureTechnology) {
326
+ const initialCount = filteredClinics.length;
327
+ filteredClinics = filteredClinics.filter(clinic => {
328
+ const proceduresInfo = clinic.proceduresInfo || [];
329
+ return proceduresInfo.some(proc => proc.technologyName === filters.procedureTechnology);
330
+ });
331
+ console.log(`[CLINIC_SERVICE] Applied procedure technology filter: ${initialCount} → ${filteredClinics.length}`);
332
+ }
333
+
334
+ // ✅ Geo-radius filter (postojeći kod)
287
335
  if (filters.center && filters.radiusInKm) {
288
- clinics = clinics.filter(clinic => {
336
+ const initialCount = filteredClinics.length;
337
+ filteredClinics = filteredClinics.filter(clinic => {
338
+ if (!clinic.location?.latitude || !clinic.location?.longitude) {
339
+ console.log(`[CLINIC_SERVICE] Clinic ${clinic.id} missing location data`);
340
+ return false;
341
+ }
342
+
289
343
  const distance = distanceBetween(
290
- [filters.center!.latitude, filters.center!.longitude],
344
+ [filters.center.latitude, filters.center.longitude],
291
345
  [clinic.location.latitude, clinic.location.longitude]
292
346
  ) / 1000; // Convert to km
293
347
 
348
+ console.log(`[CLINIC_SERVICE] Clinic ${clinic.name}: distance ${distance.toFixed(2)}km (limit: ${filters.radiusInKm}km)`);
349
+
294
350
  // Attach distance for frontend sorting/display
295
351
  (clinic as any).distance = distance;
296
- return distance <= filters.radiusInKm!;
352
+ return distance <= filters.radiusInKm;
297
353
  });
354
+ console.log(`[CLINIC_SERVICE] Applied geo filter (${filters.radiusInKm}km): ${initialCount} → ${filteredClinics.length}`);
298
355
 
299
356
  // Sort by distance when geo filtering is applied
300
- clinics.sort((a, b) => ((a as any).distance || 0) - ((b as any).distance || 0));
357
+ filteredClinics.sort((a, b) => ((a as any).distance || 0) - ((b as any).distance || 0));
301
358
  }
302
-
303
- return clinics as (Clinic & { distance?: number })[];
359
+
360
+ console.log(`[CLINIC_SERVICE] Final filtered result: ${filteredClinics.length} clinics`);
361
+ return filteredClinics as (Clinic & { distance?: number })[];
304
362
  }