@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 +79 -31
- package/dist/index.mjs +79 -31
- package/package.json +1 -1
- package/src/services/clinic/utils/filter.utils.ts +103 -45
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
@@ -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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
357
|
+
filteredClinics.sort((a, b) => ((a as any).distance || 0) - ((b as any).distance || 0));
|
|
301
358
|
}
|
|
302
|
-
|
|
303
|
-
|
|
359
|
+
|
|
360
|
+
console.log(`[CLINIC_SERVICE] Final filtered result: ${filteredClinics.length} clinics`);
|
|
361
|
+
return filteredClinics as (Clinic & { distance?: number })[];
|
|
304
362
|
}
|