@blackcode_sa/metaestetics-api 1.8.15 → 1.8.16
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.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +189 -59
- package/dist/index.mjs +189 -59
- package/package.json +1 -1
- package/src/services/practitioner/practitioner.service.ts +118 -33
- package/src/services/procedure/procedure.service.ts +111 -44
package/dist/index.d.mts
CHANGED
|
@@ -4266,6 +4266,11 @@ declare class ProcedureService extends BaseService {
|
|
|
4266
4266
|
})[];
|
|
4267
4267
|
lastDoc: any;
|
|
4268
4268
|
}>;
|
|
4269
|
+
/**
|
|
4270
|
+
* Applies in-memory filters to procedures array
|
|
4271
|
+
* Used when Firestore queries fail or for complex filtering
|
|
4272
|
+
*/
|
|
4273
|
+
private applyInMemoryFilters;
|
|
4269
4274
|
private handleGeoQuery;
|
|
4270
4275
|
/**
|
|
4271
4276
|
* Creates a consultation procedure without requiring a product
|
|
@@ -4465,6 +4470,11 @@ declare class PractitionerService extends BaseService {
|
|
|
4465
4470
|
practitioners: Practitioner[];
|
|
4466
4471
|
lastDoc: any;
|
|
4467
4472
|
}>;
|
|
4473
|
+
/**
|
|
4474
|
+
* Applies in-memory filters to practitioners array
|
|
4475
|
+
* Used when Firestore queries fail or for complex filtering
|
|
4476
|
+
*/
|
|
4477
|
+
private applyInMemoryFilters;
|
|
4468
4478
|
/**
|
|
4469
4479
|
* Enables free consultation for a practitioner in a specific clinic
|
|
4470
4480
|
* Creates a free consultation procedure with hardcoded parameters
|
package/dist/index.d.ts
CHANGED
|
@@ -4266,6 +4266,11 @@ declare class ProcedureService extends BaseService {
|
|
|
4266
4266
|
})[];
|
|
4267
4267
|
lastDoc: any;
|
|
4268
4268
|
}>;
|
|
4269
|
+
/**
|
|
4270
|
+
* Applies in-memory filters to procedures array
|
|
4271
|
+
* Used when Firestore queries fail or for complex filtering
|
|
4272
|
+
*/
|
|
4273
|
+
private applyInMemoryFilters;
|
|
4269
4274
|
private handleGeoQuery;
|
|
4270
4275
|
/**
|
|
4271
4276
|
* Creates a consultation procedure without requiring a product
|
|
@@ -4465,6 +4470,11 @@ declare class PractitionerService extends BaseService {
|
|
|
4465
4470
|
practitioners: Practitioner[];
|
|
4466
4471
|
lastDoc: any;
|
|
4467
4472
|
}>;
|
|
4473
|
+
/**
|
|
4474
|
+
* Applies in-memory filters to practitioners array
|
|
4475
|
+
* Used when Firestore queries fail or for complex filtering
|
|
4476
|
+
*/
|
|
4477
|
+
private applyInMemoryFilters;
|
|
4468
4478
|
/**
|
|
4469
4479
|
* Enables free consultation for a practitioner in a specific clinic
|
|
4470
4480
|
* Creates a free consultation procedure with hardcoded parameters
|
package/dist/index.js
CHANGED
|
@@ -6889,8 +6889,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6889
6889
|
}
|
|
6890
6890
|
constraints.push((0, import_firestore21.where)("isActive", "==", true));
|
|
6891
6891
|
if (filters.certifications && filters.certifications.length > 0) {
|
|
6892
|
+
const certificationsToMatch = filters.certifications;
|
|
6892
6893
|
constraints.push(
|
|
6893
|
-
(0, import_firestore21.where)("certification.specialties", "array-contains-any",
|
|
6894
|
+
(0, import_firestore21.where)("certification.specialties", "array-contains-any", certificationsToMatch)
|
|
6894
6895
|
);
|
|
6895
6896
|
}
|
|
6896
6897
|
if (filters.minRating !== void 0) {
|
|
@@ -6933,18 +6934,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6933
6934
|
});
|
|
6934
6935
|
practitioners = practitioners.slice(0, filters.pagination || 10);
|
|
6935
6936
|
}
|
|
6936
|
-
|
|
6937
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
6938
|
-
practitioners = practitioners.filter((practitioner) => {
|
|
6939
|
-
var _a, _b;
|
|
6940
|
-
const firstName = (((_a = practitioner.basicInfo) == null ? void 0 : _a.firstName) || "").toLowerCase();
|
|
6941
|
-
const lastName = (((_b = practitioner.basicInfo) == null ? void 0 : _b.lastName) || "").toLowerCase();
|
|
6942
|
-
const fullName = `${firstName} ${lastName}`.trim();
|
|
6943
|
-
const fullNameLower = practitioner.fullNameLower || "";
|
|
6944
|
-
return firstName.includes(searchTerm) || lastName.includes(searchTerm) || fullName.includes(searchTerm) || fullNameLower.includes(searchTerm);
|
|
6945
|
-
});
|
|
6946
|
-
console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${practitioners.length}`);
|
|
6947
|
-
}
|
|
6937
|
+
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6948
6938
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6949
6939
|
console.log(`[PRACTITIONER_SERVICE] Strategy 2 success: ${practitioners.length} practitioners`);
|
|
6950
6940
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
@@ -6964,18 +6954,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6964
6954
|
const q = (0, import_firestore21.query)((0, import_firestore21.collection)(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
6965
6955
|
const querySnapshot = await (0, import_firestore21.getDocs)(q);
|
|
6966
6956
|
let practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
|
|
6967
|
-
|
|
6968
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
6969
|
-
practitioners = practitioners.filter((practitioner) => {
|
|
6970
|
-
var _a, _b;
|
|
6971
|
-
const firstName = (((_a = practitioner.basicInfo) == null ? void 0 : _a.firstName) || "").toLowerCase();
|
|
6972
|
-
const lastName = (((_b = practitioner.basicInfo) == null ? void 0 : _b.lastName) || "").toLowerCase();
|
|
6973
|
-
const fullName = `${firstName} ${lastName}`.trim();
|
|
6974
|
-
const fullNameLower = practitioner.fullNameLower || "";
|
|
6975
|
-
return firstName.includes(searchTerm) || lastName.includes(searchTerm) || fullName.includes(searchTerm) || fullNameLower.includes(searchTerm);
|
|
6976
|
-
});
|
|
6977
|
-
console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${practitioners.length}`);
|
|
6978
|
-
}
|
|
6957
|
+
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6979
6958
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6980
6959
|
console.log(`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`);
|
|
6981
6960
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
@@ -6992,6 +6971,98 @@ var PractitionerService = class extends BaseService {
|
|
|
6992
6971
|
return { practitioners: [], lastDoc: null };
|
|
6993
6972
|
}
|
|
6994
6973
|
}
|
|
6974
|
+
/**
|
|
6975
|
+
* Applies in-memory filters to practitioners array
|
|
6976
|
+
* Used when Firestore queries fail or for complex filtering
|
|
6977
|
+
*/
|
|
6978
|
+
applyInMemoryFilters(practitioners, filters) {
|
|
6979
|
+
let filteredPractitioners = [...practitioners];
|
|
6980
|
+
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
6981
|
+
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
6982
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
6983
|
+
var _a, _b;
|
|
6984
|
+
const firstName = (((_a = practitioner.basicInfo) == null ? void 0 : _a.firstName) || "").toLowerCase();
|
|
6985
|
+
const lastName = (((_b = practitioner.basicInfo) == null ? void 0 : _b.lastName) || "").toLowerCase();
|
|
6986
|
+
const fullName = `${firstName} ${lastName}`.trim();
|
|
6987
|
+
const fullNameLower = practitioner.fullNameLower || "";
|
|
6988
|
+
return firstName.includes(searchTerm) || lastName.includes(searchTerm) || fullName.includes(searchTerm) || fullNameLower.includes(searchTerm);
|
|
6989
|
+
});
|
|
6990
|
+
console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${filteredPractitioners.length}`);
|
|
6991
|
+
}
|
|
6992
|
+
if (filters.certifications && filters.certifications.length > 0) {
|
|
6993
|
+
const certificationsToMatch = filters.certifications;
|
|
6994
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
6995
|
+
var _a;
|
|
6996
|
+
const practitionerCerts = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
|
|
6997
|
+
return certificationsToMatch.some((cert) => practitionerCerts.includes(cert));
|
|
6998
|
+
});
|
|
6999
|
+
console.log(`[PRACTITIONER_SERVICE] Applied certifications filter, results: ${filteredPractitioners.length}`);
|
|
7000
|
+
}
|
|
7001
|
+
if (filters.specialties && filters.specialties.length > 0) {
|
|
7002
|
+
const specialtiesToMatch = filters.specialties;
|
|
7003
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7004
|
+
var _a;
|
|
7005
|
+
const practitionerSpecs = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
|
|
7006
|
+
return specialtiesToMatch.some((spec) => practitionerSpecs.includes(spec));
|
|
7007
|
+
});
|
|
7008
|
+
console.log(`[PRACTITIONER_SERVICE] Applied specialties filter, results: ${filteredPractitioners.length}`);
|
|
7009
|
+
}
|
|
7010
|
+
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
7011
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7012
|
+
var _a;
|
|
7013
|
+
const rating = ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
7014
|
+
if (filters.minRating !== void 0 && rating < filters.minRating) return false;
|
|
7015
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
7016
|
+
return true;
|
|
7017
|
+
});
|
|
7018
|
+
console.log(`[PRACTITIONER_SERVICE] Applied rating filter, results: ${filteredPractitioners.length}`);
|
|
7019
|
+
}
|
|
7020
|
+
if (filters.procedureFamily) {
|
|
7021
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7022
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7023
|
+
return proceduresInfo.some((proc) => proc.family === filters.procedureFamily);
|
|
7024
|
+
});
|
|
7025
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure family filter, results: ${filteredPractitioners.length}`);
|
|
7026
|
+
}
|
|
7027
|
+
if (filters.procedureCategory) {
|
|
7028
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7029
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7030
|
+
return proceduresInfo.some((proc) => proc.categoryName === filters.procedureCategory);
|
|
7031
|
+
});
|
|
7032
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure category filter, results: ${filteredPractitioners.length}`);
|
|
7033
|
+
}
|
|
7034
|
+
if (filters.procedureSubcategory) {
|
|
7035
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7036
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7037
|
+
return proceduresInfo.some((proc) => proc.subcategoryName === filters.procedureSubcategory);
|
|
7038
|
+
});
|
|
7039
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure subcategory filter, results: ${filteredPractitioners.length}`);
|
|
7040
|
+
}
|
|
7041
|
+
if (filters.procedureTechnology) {
|
|
7042
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7043
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7044
|
+
return proceduresInfo.some((proc) => proc.technologyName === filters.procedureTechnology);
|
|
7045
|
+
});
|
|
7046
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure technology filter, results: ${filteredPractitioners.length}`);
|
|
7047
|
+
}
|
|
7048
|
+
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
7049
|
+
const location = filters.location;
|
|
7050
|
+
const radiusInKm = filters.radiusInKm;
|
|
7051
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7052
|
+
const clinics = practitioner.clinicsInfo || [];
|
|
7053
|
+
return clinics.some((clinic) => {
|
|
7054
|
+
const distance = (0, import_geofire_common2.distanceBetween)(
|
|
7055
|
+
[location.latitude, location.longitude],
|
|
7056
|
+
[clinic.location.latitude, clinic.location.longitude]
|
|
7057
|
+
);
|
|
7058
|
+
const distanceInKm = distance / 1e3;
|
|
7059
|
+
return distanceInKm <= radiusInKm;
|
|
7060
|
+
});
|
|
7061
|
+
});
|
|
7062
|
+
console.log(`[PRACTITIONER_SERVICE] Applied geo filter, results: ${filteredPractitioners.length}`);
|
|
7063
|
+
}
|
|
7064
|
+
return filteredPractitioners;
|
|
7065
|
+
}
|
|
6995
7066
|
/**
|
|
6996
7067
|
* Enables free consultation for a practitioner in a specific clinic
|
|
6997
7068
|
* Creates a free consultation procedure with hardcoded parameters
|
|
@@ -15173,7 +15244,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15173
15244
|
constraints.push((0, import_firestore45.where)("reviewInfo.averageRating", "<=", filters.maxRating));
|
|
15174
15245
|
}
|
|
15175
15246
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15176
|
-
|
|
15247
|
+
const benefitsToMatch = filters.treatmentBenefits;
|
|
15248
|
+
constraints.push((0, import_firestore45.where)("treatmentBenefits", "array-contains-any", benefitsToMatch));
|
|
15177
15249
|
}
|
|
15178
15250
|
return constraints;
|
|
15179
15251
|
};
|
|
@@ -15256,15 +15328,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15256
15328
|
const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15257
15329
|
const querySnapshot = await (0, import_firestore45.getDocs)(q);
|
|
15258
15330
|
let procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
|
|
15259
|
-
|
|
15260
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15261
|
-
procedures = procedures.filter((procedure) => {
|
|
15262
|
-
const name = (procedure.name || "").toLowerCase();
|
|
15263
|
-
const nameLower = procedure.nameLower || "";
|
|
15264
|
-
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15265
|
-
});
|
|
15266
|
-
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${procedures.length}`);
|
|
15267
|
-
}
|
|
15331
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15268
15332
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15269
15333
|
console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
|
|
15270
15334
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -15284,15 +15348,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15284
15348
|
const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15285
15349
|
const querySnapshot = await (0, import_firestore45.getDocs)(q);
|
|
15286
15350
|
let procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
|
|
15287
|
-
|
|
15288
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15289
|
-
procedures = procedures.filter((procedure) => {
|
|
15290
|
-
const name = (procedure.name || "").toLowerCase();
|
|
15291
|
-
const nameLower = procedure.nameLower || "";
|
|
15292
|
-
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15293
|
-
});
|
|
15294
|
-
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${procedures.length}`);
|
|
15295
|
-
}
|
|
15351
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15296
15352
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15297
15353
|
console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
|
|
15298
15354
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -15309,6 +15365,94 @@ var ProcedureService = class extends BaseService {
|
|
|
15309
15365
|
return { procedures: [], lastDoc: null };
|
|
15310
15366
|
}
|
|
15311
15367
|
}
|
|
15368
|
+
/**
|
|
15369
|
+
* Applies in-memory filters to procedures array
|
|
15370
|
+
* Used when Firestore queries fail or for complex filtering
|
|
15371
|
+
*/
|
|
15372
|
+
applyInMemoryFilters(procedures, filters) {
|
|
15373
|
+
let filteredProcedures = [...procedures];
|
|
15374
|
+
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15375
|
+
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15376
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15377
|
+
const name = (procedure.name || "").toLowerCase();
|
|
15378
|
+
const nameLower = procedure.nameLower || "";
|
|
15379
|
+
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15380
|
+
});
|
|
15381
|
+
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`);
|
|
15382
|
+
}
|
|
15383
|
+
if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
|
|
15384
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15385
|
+
const price = procedure.price || 0;
|
|
15386
|
+
if (filters.minPrice !== void 0 && price < filters.minPrice) return false;
|
|
15387
|
+
if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
|
|
15388
|
+
return true;
|
|
15389
|
+
});
|
|
15390
|
+
console.log(`[PROCEDURE_SERVICE] Applied price filter (${filters.minPrice}-${filters.maxPrice}), results: ${filteredProcedures.length}`);
|
|
15391
|
+
}
|
|
15392
|
+
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
15393
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15394
|
+
var _a;
|
|
15395
|
+
const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
15396
|
+
if (filters.minRating !== void 0 && rating < filters.minRating) return false;
|
|
15397
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
15398
|
+
return true;
|
|
15399
|
+
});
|
|
15400
|
+
console.log(`[PROCEDURE_SERVICE] Applied rating filter, results: ${filteredProcedures.length}`);
|
|
15401
|
+
}
|
|
15402
|
+
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15403
|
+
const benefitsToMatch = filters.treatmentBenefits;
|
|
15404
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15405
|
+
const procedureBenefits = procedure.treatmentBenefits || [];
|
|
15406
|
+
return benefitsToMatch.some((benefit) => procedureBenefits.includes(benefit));
|
|
15407
|
+
});
|
|
15408
|
+
console.log(`[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`);
|
|
15409
|
+
}
|
|
15410
|
+
if (filters.procedureFamily) {
|
|
15411
|
+
filteredProcedures = filteredProcedures.filter((procedure) => procedure.family === filters.procedureFamily);
|
|
15412
|
+
console.log(`[PROCEDURE_SERVICE] Applied family filter, results: ${filteredProcedures.length}`);
|
|
15413
|
+
}
|
|
15414
|
+
if (filters.procedureCategory) {
|
|
15415
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15416
|
+
var _a;
|
|
15417
|
+
return ((_a = procedure.category) == null ? void 0 : _a.id) === filters.procedureCategory;
|
|
15418
|
+
});
|
|
15419
|
+
console.log(`[PROCEDURE_SERVICE] Applied category filter, results: ${filteredProcedures.length}`);
|
|
15420
|
+
}
|
|
15421
|
+
if (filters.procedureSubcategory) {
|
|
15422
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15423
|
+
var _a;
|
|
15424
|
+
return ((_a = procedure.subcategory) == null ? void 0 : _a.id) === filters.procedureSubcategory;
|
|
15425
|
+
});
|
|
15426
|
+
console.log(`[PROCEDURE_SERVICE] Applied subcategory filter, results: ${filteredProcedures.length}`);
|
|
15427
|
+
}
|
|
15428
|
+
if (filters.procedureTechnology) {
|
|
15429
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15430
|
+
var _a;
|
|
15431
|
+
return ((_a = procedure.technology) == null ? void 0 : _a.id) === filters.procedureTechnology;
|
|
15432
|
+
});
|
|
15433
|
+
console.log(`[PROCEDURE_SERVICE] Applied technology filter, results: ${filteredProcedures.length}`);
|
|
15434
|
+
}
|
|
15435
|
+
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
15436
|
+
const location = filters.location;
|
|
15437
|
+
const radiusInKm = filters.radiusInKm;
|
|
15438
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15439
|
+
var _a;
|
|
15440
|
+
const clinicLocation = (_a = procedure.clinicInfo) == null ? void 0 : _a.location;
|
|
15441
|
+
if (!(clinicLocation == null ? void 0 : clinicLocation.latitude) || !(clinicLocation == null ? void 0 : clinicLocation.longitude)) {
|
|
15442
|
+
return false;
|
|
15443
|
+
}
|
|
15444
|
+
const distance = (0, import_geofire_common8.distanceBetween)(
|
|
15445
|
+
[location.latitude, location.longitude],
|
|
15446
|
+
[clinicLocation.latitude, clinicLocation.longitude]
|
|
15447
|
+
) / 1e3;
|
|
15448
|
+
procedure.distance = distance;
|
|
15449
|
+
return distance <= radiusInKm;
|
|
15450
|
+
});
|
|
15451
|
+
console.log(`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`);
|
|
15452
|
+
filteredProcedures.sort((a, b) => (a.distance || 0) - (b.distance || 0));
|
|
15453
|
+
}
|
|
15454
|
+
return filteredProcedures;
|
|
15455
|
+
}
|
|
15312
15456
|
handleGeoQuery(filters) {
|
|
15313
15457
|
console.log("[PROCEDURE_SERVICE] Executing geo query with enhanced debugging");
|
|
15314
15458
|
try {
|
|
@@ -15329,21 +15473,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15329
15473
|
const q = (0, import_firestore45.query)((0, import_firestore45.collection)(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15330
15474
|
return (0, import_firestore45.getDocs)(q).then((querySnapshot) => {
|
|
15331
15475
|
let procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
|
|
15332
|
-
procedures =
|
|
15333
|
-
var _a;
|
|
15334
|
-
const clinicLocation = (_a = procedure.clinicInfo) == null ? void 0 : _a.location;
|
|
15335
|
-
if (!(clinicLocation == null ? void 0 : clinicLocation.latitude) || !(clinicLocation == null ? void 0 : clinicLocation.longitude)) {
|
|
15336
|
-
return false;
|
|
15337
|
-
}
|
|
15338
|
-
const distance = (0, import_geofire_common8.distanceBetween)(
|
|
15339
|
-
[location.latitude, location.longitude],
|
|
15340
|
-
[clinicLocation.latitude, clinicLocation.longitude]
|
|
15341
|
-
) / 1e3;
|
|
15342
|
-
procedure.distance = distance;
|
|
15343
|
-
return distance <= radiusInKm;
|
|
15344
|
-
});
|
|
15345
|
-
procedures.sort((a, b) => (a.distance || 0) - (b.distance || 0));
|
|
15346
|
-
procedures = procedures.slice(0, filters.pagination || 10);
|
|
15476
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15347
15477
|
console.log(`[PROCEDURE_SERVICE] Geo query success: ${procedures.length} procedures within ${radiusInKm}km`);
|
|
15348
15478
|
const lastDoc = procedures.length < (filters.pagination || 10) ? null : querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
15349
15479
|
return { procedures, lastDoc };
|
package/dist/index.mjs
CHANGED
|
@@ -6935,8 +6935,9 @@ var PractitionerService = class extends BaseService {
|
|
|
6935
6935
|
}
|
|
6936
6936
|
constraints.push(where10("isActive", "==", true));
|
|
6937
6937
|
if (filters.certifications && filters.certifications.length > 0) {
|
|
6938
|
+
const certificationsToMatch = filters.certifications;
|
|
6938
6939
|
constraints.push(
|
|
6939
|
-
where10("certification.specialties", "array-contains-any",
|
|
6940
|
+
where10("certification.specialties", "array-contains-any", certificationsToMatch)
|
|
6940
6941
|
);
|
|
6941
6942
|
}
|
|
6942
6943
|
if (filters.minRating !== void 0) {
|
|
@@ -6979,18 +6980,7 @@ var PractitionerService = class extends BaseService {
|
|
|
6979
6980
|
});
|
|
6980
6981
|
practitioners = practitioners.slice(0, filters.pagination || 10);
|
|
6981
6982
|
}
|
|
6982
|
-
|
|
6983
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
6984
|
-
practitioners = practitioners.filter((practitioner) => {
|
|
6985
|
-
var _a, _b;
|
|
6986
|
-
const firstName = (((_a = practitioner.basicInfo) == null ? void 0 : _a.firstName) || "").toLowerCase();
|
|
6987
|
-
const lastName = (((_b = practitioner.basicInfo) == null ? void 0 : _b.lastName) || "").toLowerCase();
|
|
6988
|
-
const fullName = `${firstName} ${lastName}`.trim();
|
|
6989
|
-
const fullNameLower = practitioner.fullNameLower || "";
|
|
6990
|
-
return firstName.includes(searchTerm) || lastName.includes(searchTerm) || fullName.includes(searchTerm) || fullNameLower.includes(searchTerm);
|
|
6991
|
-
});
|
|
6992
|
-
console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${practitioners.length}`);
|
|
6993
|
-
}
|
|
6983
|
+
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
6994
6984
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
6995
6985
|
console.log(`[PRACTITIONER_SERVICE] Strategy 2 success: ${practitioners.length} practitioners`);
|
|
6996
6986
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
@@ -7010,18 +7000,7 @@ var PractitionerService = class extends BaseService {
|
|
|
7010
7000
|
const q = query10(collection10(this.db, PRACTITIONERS_COLLECTION), ...constraints);
|
|
7011
7001
|
const querySnapshot = await getDocs10(q);
|
|
7012
7002
|
let practitioners = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
|
|
7013
|
-
|
|
7014
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
7015
|
-
practitioners = practitioners.filter((practitioner) => {
|
|
7016
|
-
var _a, _b;
|
|
7017
|
-
const firstName = (((_a = practitioner.basicInfo) == null ? void 0 : _a.firstName) || "").toLowerCase();
|
|
7018
|
-
const lastName = (((_b = practitioner.basicInfo) == null ? void 0 : _b.lastName) || "").toLowerCase();
|
|
7019
|
-
const fullName = `${firstName} ${lastName}`.trim();
|
|
7020
|
-
const fullNameLower = practitioner.fullNameLower || "";
|
|
7021
|
-
return firstName.includes(searchTerm) || lastName.includes(searchTerm) || fullName.includes(searchTerm) || fullNameLower.includes(searchTerm);
|
|
7022
|
-
});
|
|
7023
|
-
console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${practitioners.length}`);
|
|
7024
|
-
}
|
|
7003
|
+
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
7025
7004
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
7026
7005
|
console.log(`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`);
|
|
7027
7006
|
if (practitioners.length < (filters.pagination || 10)) {
|
|
@@ -7038,6 +7017,98 @@ var PractitionerService = class extends BaseService {
|
|
|
7038
7017
|
return { practitioners: [], lastDoc: null };
|
|
7039
7018
|
}
|
|
7040
7019
|
}
|
|
7020
|
+
/**
|
|
7021
|
+
* Applies in-memory filters to practitioners array
|
|
7022
|
+
* Used when Firestore queries fail or for complex filtering
|
|
7023
|
+
*/
|
|
7024
|
+
applyInMemoryFilters(practitioners, filters) {
|
|
7025
|
+
let filteredPractitioners = [...practitioners];
|
|
7026
|
+
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
7027
|
+
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
7028
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7029
|
+
var _a, _b;
|
|
7030
|
+
const firstName = (((_a = practitioner.basicInfo) == null ? void 0 : _a.firstName) || "").toLowerCase();
|
|
7031
|
+
const lastName = (((_b = practitioner.basicInfo) == null ? void 0 : _b.lastName) || "").toLowerCase();
|
|
7032
|
+
const fullName = `${firstName} ${lastName}`.trim();
|
|
7033
|
+
const fullNameLower = practitioner.fullNameLower || "";
|
|
7034
|
+
return firstName.includes(searchTerm) || lastName.includes(searchTerm) || fullName.includes(searchTerm) || fullNameLower.includes(searchTerm);
|
|
7035
|
+
});
|
|
7036
|
+
console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${filteredPractitioners.length}`);
|
|
7037
|
+
}
|
|
7038
|
+
if (filters.certifications && filters.certifications.length > 0) {
|
|
7039
|
+
const certificationsToMatch = filters.certifications;
|
|
7040
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7041
|
+
var _a;
|
|
7042
|
+
const practitionerCerts = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
|
|
7043
|
+
return certificationsToMatch.some((cert) => practitionerCerts.includes(cert));
|
|
7044
|
+
});
|
|
7045
|
+
console.log(`[PRACTITIONER_SERVICE] Applied certifications filter, results: ${filteredPractitioners.length}`);
|
|
7046
|
+
}
|
|
7047
|
+
if (filters.specialties && filters.specialties.length > 0) {
|
|
7048
|
+
const specialtiesToMatch = filters.specialties;
|
|
7049
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7050
|
+
var _a;
|
|
7051
|
+
const practitionerSpecs = ((_a = practitioner.certification) == null ? void 0 : _a.specialties) || [];
|
|
7052
|
+
return specialtiesToMatch.some((spec) => practitionerSpecs.includes(spec));
|
|
7053
|
+
});
|
|
7054
|
+
console.log(`[PRACTITIONER_SERVICE] Applied specialties filter, results: ${filteredPractitioners.length}`);
|
|
7055
|
+
}
|
|
7056
|
+
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
7057
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7058
|
+
var _a;
|
|
7059
|
+
const rating = ((_a = practitioner.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
7060
|
+
if (filters.minRating !== void 0 && rating < filters.minRating) return false;
|
|
7061
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
7062
|
+
return true;
|
|
7063
|
+
});
|
|
7064
|
+
console.log(`[PRACTITIONER_SERVICE] Applied rating filter, results: ${filteredPractitioners.length}`);
|
|
7065
|
+
}
|
|
7066
|
+
if (filters.procedureFamily) {
|
|
7067
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7068
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7069
|
+
return proceduresInfo.some((proc) => proc.family === filters.procedureFamily);
|
|
7070
|
+
});
|
|
7071
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure family filter, results: ${filteredPractitioners.length}`);
|
|
7072
|
+
}
|
|
7073
|
+
if (filters.procedureCategory) {
|
|
7074
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7075
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7076
|
+
return proceduresInfo.some((proc) => proc.categoryName === filters.procedureCategory);
|
|
7077
|
+
});
|
|
7078
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure category filter, results: ${filteredPractitioners.length}`);
|
|
7079
|
+
}
|
|
7080
|
+
if (filters.procedureSubcategory) {
|
|
7081
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7082
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7083
|
+
return proceduresInfo.some((proc) => proc.subcategoryName === filters.procedureSubcategory);
|
|
7084
|
+
});
|
|
7085
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure subcategory filter, results: ${filteredPractitioners.length}`);
|
|
7086
|
+
}
|
|
7087
|
+
if (filters.procedureTechnology) {
|
|
7088
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7089
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
7090
|
+
return proceduresInfo.some((proc) => proc.technologyName === filters.procedureTechnology);
|
|
7091
|
+
});
|
|
7092
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure technology filter, results: ${filteredPractitioners.length}`);
|
|
7093
|
+
}
|
|
7094
|
+
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
7095
|
+
const location = filters.location;
|
|
7096
|
+
const radiusInKm = filters.radiusInKm;
|
|
7097
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
7098
|
+
const clinics = practitioner.clinicsInfo || [];
|
|
7099
|
+
return clinics.some((clinic) => {
|
|
7100
|
+
const distance = distanceBetween(
|
|
7101
|
+
[location.latitude, location.longitude],
|
|
7102
|
+
[clinic.location.latitude, clinic.location.longitude]
|
|
7103
|
+
);
|
|
7104
|
+
const distanceInKm = distance / 1e3;
|
|
7105
|
+
return distanceInKm <= radiusInKm;
|
|
7106
|
+
});
|
|
7107
|
+
});
|
|
7108
|
+
console.log(`[PRACTITIONER_SERVICE] Applied geo filter, results: ${filteredPractitioners.length}`);
|
|
7109
|
+
}
|
|
7110
|
+
return filteredPractitioners;
|
|
7111
|
+
}
|
|
7041
7112
|
/**
|
|
7042
7113
|
* Enables free consultation for a practitioner in a specific clinic
|
|
7043
7114
|
* Creates a free consultation procedure with hardcoded parameters
|
|
@@ -15424,7 +15495,8 @@ var ProcedureService = class extends BaseService {
|
|
|
15424
15495
|
constraints.push(where29("reviewInfo.averageRating", "<=", filters.maxRating));
|
|
15425
15496
|
}
|
|
15426
15497
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15427
|
-
|
|
15498
|
+
const benefitsToMatch = filters.treatmentBenefits;
|
|
15499
|
+
constraints.push(where29("treatmentBenefits", "array-contains-any", benefitsToMatch));
|
|
15428
15500
|
}
|
|
15429
15501
|
return constraints;
|
|
15430
15502
|
};
|
|
@@ -15507,15 +15579,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15507
15579
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15508
15580
|
const querySnapshot = await getDocs29(q);
|
|
15509
15581
|
let procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
|
|
15510
|
-
|
|
15511
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15512
|
-
procedures = procedures.filter((procedure) => {
|
|
15513
|
-
const name = (procedure.name || "").toLowerCase();
|
|
15514
|
-
const nameLower = procedure.nameLower || "";
|
|
15515
|
-
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15516
|
-
});
|
|
15517
|
-
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${procedures.length}`);
|
|
15518
|
-
}
|
|
15582
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15519
15583
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15520
15584
|
console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
|
|
15521
15585
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -15535,15 +15599,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15535
15599
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15536
15600
|
const querySnapshot = await getDocs29(q);
|
|
15537
15601
|
let procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
|
|
15538
|
-
|
|
15539
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15540
|
-
procedures = procedures.filter((procedure) => {
|
|
15541
|
-
const name = (procedure.name || "").toLowerCase();
|
|
15542
|
-
const nameLower = procedure.nameLower || "";
|
|
15543
|
-
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15544
|
-
});
|
|
15545
|
-
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${procedures.length}`);
|
|
15546
|
-
}
|
|
15602
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15547
15603
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
15548
15604
|
console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
|
|
15549
15605
|
if (procedures.length < (filters.pagination || 10)) {
|
|
@@ -15560,6 +15616,94 @@ var ProcedureService = class extends BaseService {
|
|
|
15560
15616
|
return { procedures: [], lastDoc: null };
|
|
15561
15617
|
}
|
|
15562
15618
|
}
|
|
15619
|
+
/**
|
|
15620
|
+
* Applies in-memory filters to procedures array
|
|
15621
|
+
* Used when Firestore queries fail or for complex filtering
|
|
15622
|
+
*/
|
|
15623
|
+
applyInMemoryFilters(procedures, filters) {
|
|
15624
|
+
let filteredProcedures = [...procedures];
|
|
15625
|
+
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
15626
|
+
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
15627
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15628
|
+
const name = (procedure.name || "").toLowerCase();
|
|
15629
|
+
const nameLower = procedure.nameLower || "";
|
|
15630
|
+
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
15631
|
+
});
|
|
15632
|
+
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`);
|
|
15633
|
+
}
|
|
15634
|
+
if (filters.minPrice !== void 0 || filters.maxPrice !== void 0) {
|
|
15635
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15636
|
+
const price = procedure.price || 0;
|
|
15637
|
+
if (filters.minPrice !== void 0 && price < filters.minPrice) return false;
|
|
15638
|
+
if (filters.maxPrice !== void 0 && price > filters.maxPrice) return false;
|
|
15639
|
+
return true;
|
|
15640
|
+
});
|
|
15641
|
+
console.log(`[PROCEDURE_SERVICE] Applied price filter (${filters.minPrice}-${filters.maxPrice}), results: ${filteredProcedures.length}`);
|
|
15642
|
+
}
|
|
15643
|
+
if (filters.minRating !== void 0 || filters.maxRating !== void 0) {
|
|
15644
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15645
|
+
var _a;
|
|
15646
|
+
const rating = ((_a = procedure.reviewInfo) == null ? void 0 : _a.averageRating) || 0;
|
|
15647
|
+
if (filters.minRating !== void 0 && rating < filters.minRating) return false;
|
|
15648
|
+
if (filters.maxRating !== void 0 && rating > filters.maxRating) return false;
|
|
15649
|
+
return true;
|
|
15650
|
+
});
|
|
15651
|
+
console.log(`[PROCEDURE_SERVICE] Applied rating filter, results: ${filteredProcedures.length}`);
|
|
15652
|
+
}
|
|
15653
|
+
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
15654
|
+
const benefitsToMatch = filters.treatmentBenefits;
|
|
15655
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15656
|
+
const procedureBenefits = procedure.treatmentBenefits || [];
|
|
15657
|
+
return benefitsToMatch.some((benefit) => procedureBenefits.includes(benefit));
|
|
15658
|
+
});
|
|
15659
|
+
console.log(`[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`);
|
|
15660
|
+
}
|
|
15661
|
+
if (filters.procedureFamily) {
|
|
15662
|
+
filteredProcedures = filteredProcedures.filter((procedure) => procedure.family === filters.procedureFamily);
|
|
15663
|
+
console.log(`[PROCEDURE_SERVICE] Applied family filter, results: ${filteredProcedures.length}`);
|
|
15664
|
+
}
|
|
15665
|
+
if (filters.procedureCategory) {
|
|
15666
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15667
|
+
var _a;
|
|
15668
|
+
return ((_a = procedure.category) == null ? void 0 : _a.id) === filters.procedureCategory;
|
|
15669
|
+
});
|
|
15670
|
+
console.log(`[PROCEDURE_SERVICE] Applied category filter, results: ${filteredProcedures.length}`);
|
|
15671
|
+
}
|
|
15672
|
+
if (filters.procedureSubcategory) {
|
|
15673
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15674
|
+
var _a;
|
|
15675
|
+
return ((_a = procedure.subcategory) == null ? void 0 : _a.id) === filters.procedureSubcategory;
|
|
15676
|
+
});
|
|
15677
|
+
console.log(`[PROCEDURE_SERVICE] Applied subcategory filter, results: ${filteredProcedures.length}`);
|
|
15678
|
+
}
|
|
15679
|
+
if (filters.procedureTechnology) {
|
|
15680
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15681
|
+
var _a;
|
|
15682
|
+
return ((_a = procedure.technology) == null ? void 0 : _a.id) === filters.procedureTechnology;
|
|
15683
|
+
});
|
|
15684
|
+
console.log(`[PROCEDURE_SERVICE] Applied technology filter, results: ${filteredProcedures.length}`);
|
|
15685
|
+
}
|
|
15686
|
+
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
15687
|
+
const location = filters.location;
|
|
15688
|
+
const radiusInKm = filters.radiusInKm;
|
|
15689
|
+
filteredProcedures = filteredProcedures.filter((procedure) => {
|
|
15690
|
+
var _a;
|
|
15691
|
+
const clinicLocation = (_a = procedure.clinicInfo) == null ? void 0 : _a.location;
|
|
15692
|
+
if (!(clinicLocation == null ? void 0 : clinicLocation.latitude) || !(clinicLocation == null ? void 0 : clinicLocation.longitude)) {
|
|
15693
|
+
return false;
|
|
15694
|
+
}
|
|
15695
|
+
const distance = distanceBetween6(
|
|
15696
|
+
[location.latitude, location.longitude],
|
|
15697
|
+
[clinicLocation.latitude, clinicLocation.longitude]
|
|
15698
|
+
) / 1e3;
|
|
15699
|
+
procedure.distance = distance;
|
|
15700
|
+
return distance <= radiusInKm;
|
|
15701
|
+
});
|
|
15702
|
+
console.log(`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`);
|
|
15703
|
+
filteredProcedures.sort((a, b) => (a.distance || 0) - (b.distance || 0));
|
|
15704
|
+
}
|
|
15705
|
+
return filteredProcedures;
|
|
15706
|
+
}
|
|
15563
15707
|
handleGeoQuery(filters) {
|
|
15564
15708
|
console.log("[PROCEDURE_SERVICE] Executing geo query with enhanced debugging");
|
|
15565
15709
|
try {
|
|
@@ -15580,21 +15724,7 @@ var ProcedureService = class extends BaseService {
|
|
|
15580
15724
|
const q = query29(collection29(this.db, PROCEDURES_COLLECTION), ...constraints);
|
|
15581
15725
|
return getDocs29(q).then((querySnapshot) => {
|
|
15582
15726
|
let procedures = querySnapshot.docs.map((doc37) => ({ ...doc37.data(), id: doc37.id }));
|
|
15583
|
-
procedures =
|
|
15584
|
-
var _a;
|
|
15585
|
-
const clinicLocation = (_a = procedure.clinicInfo) == null ? void 0 : _a.location;
|
|
15586
|
-
if (!(clinicLocation == null ? void 0 : clinicLocation.latitude) || !(clinicLocation == null ? void 0 : clinicLocation.longitude)) {
|
|
15587
|
-
return false;
|
|
15588
|
-
}
|
|
15589
|
-
const distance = distanceBetween6(
|
|
15590
|
-
[location.latitude, location.longitude],
|
|
15591
|
-
[clinicLocation.latitude, clinicLocation.longitude]
|
|
15592
|
-
) / 1e3;
|
|
15593
|
-
procedure.distance = distance;
|
|
15594
|
-
return distance <= radiusInKm;
|
|
15595
|
-
});
|
|
15596
|
-
procedures.sort((a, b) => (a.distance || 0) - (b.distance || 0));
|
|
15597
|
-
procedures = procedures.slice(0, filters.pagination || 10);
|
|
15727
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
15598
15728
|
console.log(`[PROCEDURE_SERVICE] Geo query success: ${procedures.length} procedures within ${radiusInKm}km`);
|
|
15599
15729
|
const lastDoc = procedures.length < (filters.pagination || 10) ? null : querySnapshot.docs[querySnapshot.docs.length - 1];
|
|
15600
15730
|
return { procedures, lastDoc };
|
package/package.json
CHANGED
|
@@ -1116,8 +1116,9 @@ export class PractitionerService extends BaseService {
|
|
|
1116
1116
|
|
|
1117
1117
|
// Add other filters that work well with Firestore
|
|
1118
1118
|
if (filters.certifications && filters.certifications.length > 0) {
|
|
1119
|
+
const certificationsToMatch = filters.certifications as CertificationSpecialty[];
|
|
1119
1120
|
constraints.push(
|
|
1120
|
-
where("certification.specialties", "array-contains-any",
|
|
1121
|
+
where("certification.specialties", "array-contains-any", certificationsToMatch)
|
|
1121
1122
|
);
|
|
1122
1123
|
}
|
|
1123
1124
|
|
|
@@ -1171,22 +1172,8 @@ export class PractitionerService extends BaseService {
|
|
|
1171
1172
|
practitioners = practitioners.slice(0, filters.pagination || 10);
|
|
1172
1173
|
}
|
|
1173
1174
|
|
|
1174
|
-
// Apply client-side
|
|
1175
|
-
|
|
1176
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
1177
|
-
practitioners = practitioners.filter(practitioner => {
|
|
1178
|
-
const firstName = (practitioner.basicInfo?.firstName || '').toLowerCase();
|
|
1179
|
-
const lastName = (practitioner.basicInfo?.lastName || '').toLowerCase();
|
|
1180
|
-
const fullName = `${firstName} ${lastName}`.trim();
|
|
1181
|
-
const fullNameLower = practitioner.fullNameLower || '';
|
|
1182
|
-
|
|
1183
|
-
return firstName.includes(searchTerm) ||
|
|
1184
|
-
lastName.includes(searchTerm) ||
|
|
1185
|
-
fullName.includes(searchTerm) ||
|
|
1186
|
-
fullNameLower.includes(searchTerm);
|
|
1187
|
-
});
|
|
1188
|
-
console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${practitioners.length}`);
|
|
1189
|
-
}
|
|
1175
|
+
// Apply all remaining client-side filters using centralized function
|
|
1176
|
+
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
1190
1177
|
|
|
1191
1178
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1192
1179
|
console.log(`[PRACTITIONER_SERVICE] Strategy 2 success: ${practitioners.length} practitioners`);
|
|
@@ -1213,22 +1200,8 @@ export class PractitionerService extends BaseService {
|
|
|
1213
1200
|
const querySnapshot = await getDocs(q);
|
|
1214
1201
|
let practitioners = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as Practitioner));
|
|
1215
1202
|
|
|
1216
|
-
// Apply client-side
|
|
1217
|
-
|
|
1218
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
1219
|
-
practitioners = practitioners.filter(practitioner => {
|
|
1220
|
-
const firstName = (practitioner.basicInfo?.firstName || '').toLowerCase();
|
|
1221
|
-
const lastName = (practitioner.basicInfo?.lastName || '').toLowerCase();
|
|
1222
|
-
const fullName = `${firstName} ${lastName}`.trim();
|
|
1223
|
-
const fullNameLower = practitioner.fullNameLower || '';
|
|
1224
|
-
|
|
1225
|
-
return firstName.includes(searchTerm) ||
|
|
1226
|
-
lastName.includes(searchTerm) ||
|
|
1227
|
-
fullName.includes(searchTerm) ||
|
|
1228
|
-
fullNameLower.includes(searchTerm);
|
|
1229
|
-
});
|
|
1230
|
-
console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${practitioners.length}`);
|
|
1231
|
-
}
|
|
1203
|
+
// Apply all client-side filters using centralized function
|
|
1204
|
+
practitioners = this.applyInMemoryFilters(practitioners, filters);
|
|
1232
1205
|
|
|
1233
1206
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1234
1207
|
console.log(`[PRACTITIONER_SERVICE] Strategy 3 success: ${practitioners.length} practitioners`);
|
|
@@ -1252,6 +1225,118 @@ export class PractitionerService extends BaseService {
|
|
|
1252
1225
|
}
|
|
1253
1226
|
}
|
|
1254
1227
|
|
|
1228
|
+
/**
|
|
1229
|
+
* Applies in-memory filters to practitioners array
|
|
1230
|
+
* Used when Firestore queries fail or for complex filtering
|
|
1231
|
+
*/
|
|
1232
|
+
private applyInMemoryFilters(practitioners: Practitioner[], filters: any): Practitioner[] {
|
|
1233
|
+
let filteredPractitioners = [...practitioners]; // Create copy to avoid mutating original
|
|
1234
|
+
|
|
1235
|
+
// Name search filter
|
|
1236
|
+
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
1237
|
+
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
1238
|
+
filteredPractitioners = filteredPractitioners.filter(practitioner => {
|
|
1239
|
+
const firstName = (practitioner.basicInfo?.firstName || '').toLowerCase();
|
|
1240
|
+
const lastName = (practitioner.basicInfo?.lastName || '').toLowerCase();
|
|
1241
|
+
const fullName = `${firstName} ${lastName}`.trim();
|
|
1242
|
+
const fullNameLower = practitioner.fullNameLower || '';
|
|
1243
|
+
|
|
1244
|
+
return firstName.includes(searchTerm) ||
|
|
1245
|
+
lastName.includes(searchTerm) ||
|
|
1246
|
+
fullName.includes(searchTerm) ||
|
|
1247
|
+
fullNameLower.includes(searchTerm);
|
|
1248
|
+
});
|
|
1249
|
+
console.log(`[PRACTITIONER_SERVICE] Applied name filter, results: ${filteredPractitioners.length}`);
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
// Certifications filtering
|
|
1253
|
+
if (filters.certifications && filters.certifications.length > 0) {
|
|
1254
|
+
const certificationsToMatch = filters.certifications;
|
|
1255
|
+
filteredPractitioners = filteredPractitioners.filter(practitioner => {
|
|
1256
|
+
const practitionerCerts = practitioner.certification?.specialties || [];
|
|
1257
|
+
return certificationsToMatch.some((cert: any) => practitionerCerts.includes(cert as CertificationSpecialty));
|
|
1258
|
+
});
|
|
1259
|
+
console.log(`[PRACTITIONER_SERVICE] Applied certifications filter, results: ${filteredPractitioners.length}`);
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// Specialties filtering
|
|
1263
|
+
if (filters.specialties && filters.specialties.length > 0) {
|
|
1264
|
+
const specialtiesToMatch = filters.specialties;
|
|
1265
|
+
filteredPractitioners = filteredPractitioners.filter(practitioner => {
|
|
1266
|
+
const practitionerSpecs = practitioner.certification?.specialties || [];
|
|
1267
|
+
return specialtiesToMatch.some((spec: any) => practitionerSpecs.includes(spec));
|
|
1268
|
+
});
|
|
1269
|
+
console.log(`[PRACTITIONER_SERVICE] Applied specialties filter, results: ${filteredPractitioners.length}`);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
// Rating filtering
|
|
1273
|
+
if (filters.minRating !== undefined || filters.maxRating !== undefined) {
|
|
1274
|
+
filteredPractitioners = filteredPractitioners.filter(practitioner => {
|
|
1275
|
+
const rating = practitioner.reviewInfo?.averageRating || 0;
|
|
1276
|
+
if (filters.minRating !== undefined && rating < filters.minRating) return false;
|
|
1277
|
+
if (filters.maxRating !== undefined && rating > filters.maxRating) return false;
|
|
1278
|
+
return true;
|
|
1279
|
+
});
|
|
1280
|
+
console.log(`[PRACTITIONER_SERVICE] Applied rating filter, results: ${filteredPractitioners.length}`);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
// Procedure family filtering
|
|
1284
|
+
if (filters.procedureFamily) {
|
|
1285
|
+
filteredPractitioners = filteredPractitioners.filter(practitioner => {
|
|
1286
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
1287
|
+
return proceduresInfo.some(proc => proc.family === filters.procedureFamily);
|
|
1288
|
+
});
|
|
1289
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure family filter, results: ${filteredPractitioners.length}`);
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// Procedure category filtering
|
|
1293
|
+
if (filters.procedureCategory) {
|
|
1294
|
+
filteredPractitioners = filteredPractitioners.filter(practitioner => {
|
|
1295
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
1296
|
+
return proceduresInfo.some(proc => proc.categoryName === filters.procedureCategory);
|
|
1297
|
+
});
|
|
1298
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure category filter, results: ${filteredPractitioners.length}`);
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
// Procedure subcategory filtering
|
|
1302
|
+
if (filters.procedureSubcategory) {
|
|
1303
|
+
filteredPractitioners = filteredPractitioners.filter(practitioner => {
|
|
1304
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
1305
|
+
return proceduresInfo.some(proc => proc.subcategoryName === filters.procedureSubcategory);
|
|
1306
|
+
});
|
|
1307
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure subcategory filter, results: ${filteredPractitioners.length}`);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// Procedure technology filtering
|
|
1311
|
+
if (filters.procedureTechnology) {
|
|
1312
|
+
filteredPractitioners = filteredPractitioners.filter(practitioner => {
|
|
1313
|
+
const proceduresInfo = practitioner.proceduresInfo || [];
|
|
1314
|
+
return proceduresInfo.some(proc => proc.technologyName === filters.procedureTechnology);
|
|
1315
|
+
});
|
|
1316
|
+
console.log(`[PRACTITIONER_SERVICE] Applied procedure technology filter, results: ${filteredPractitioners.length}`);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// Geo-radius filter
|
|
1320
|
+
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
1321
|
+
const location = filters.location;
|
|
1322
|
+
const radiusInKm = filters.radiusInKm;
|
|
1323
|
+
filteredPractitioners = filteredPractitioners.filter((practitioner) => {
|
|
1324
|
+
const clinics = practitioner.clinicsInfo || [];
|
|
1325
|
+
return clinics.some((clinic) => {
|
|
1326
|
+
const distance = distanceBetween(
|
|
1327
|
+
[location.latitude, location.longitude],
|
|
1328
|
+
[clinic.location.latitude, clinic.location.longitude]
|
|
1329
|
+
);
|
|
1330
|
+
const distanceInKm = distance / 1000;
|
|
1331
|
+
return distanceInKm <= radiusInKm;
|
|
1332
|
+
});
|
|
1333
|
+
});
|
|
1334
|
+
console.log(`[PRACTITIONER_SERVICE] Applied geo filter, results: ${filteredPractitioners.length}`);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
return filteredPractitioners;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1255
1340
|
/**
|
|
1256
1341
|
* Enables free consultation for a practitioner in a specific clinic
|
|
1257
1342
|
* Creates a free consultation procedure with hardcoded parameters
|
|
@@ -960,7 +960,8 @@ export class ProcedureService extends BaseService {
|
|
|
960
960
|
constraints.push(where("reviewInfo.averageRating", "<=", filters.maxRating));
|
|
961
961
|
}
|
|
962
962
|
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
963
|
-
|
|
963
|
+
const benefitsToMatch = filters.treatmentBenefits;
|
|
964
|
+
constraints.push(where("treatmentBenefits", "array-contains-any", benefitsToMatch));
|
|
964
965
|
}
|
|
965
966
|
|
|
966
967
|
return constraints;
|
|
@@ -1063,16 +1064,8 @@ export class ProcedureService extends BaseService {
|
|
|
1063
1064
|
const querySnapshot = await getDocs(q);
|
|
1064
1065
|
let procedures = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as Procedure));
|
|
1065
1066
|
|
|
1066
|
-
//
|
|
1067
|
-
|
|
1068
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
1069
|
-
procedures = procedures.filter(procedure => {
|
|
1070
|
-
const name = (procedure.name || '').toLowerCase();
|
|
1071
|
-
const nameLower = procedure.nameLower || '';
|
|
1072
|
-
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
1073
|
-
});
|
|
1074
|
-
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${procedures.length}`);
|
|
1075
|
-
}
|
|
1067
|
+
// Apply all client-side filters using centralized function
|
|
1068
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
1076
1069
|
|
|
1077
1070
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1078
1071
|
console.log(`[PROCEDURE_SERVICE] Strategy 3 success: ${procedures.length} procedures`);
|
|
@@ -1099,16 +1092,8 @@ export class ProcedureService extends BaseService {
|
|
|
1099
1092
|
const querySnapshot = await getDocs(q);
|
|
1100
1093
|
let procedures = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as Procedure));
|
|
1101
1094
|
|
|
1102
|
-
//
|
|
1103
|
-
|
|
1104
|
-
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
1105
|
-
procedures = procedures.filter(procedure => {
|
|
1106
|
-
const name = (procedure.name || '').toLowerCase();
|
|
1107
|
-
const nameLower = procedure.nameLower || '';
|
|
1108
|
-
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
1109
|
-
});
|
|
1110
|
-
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${procedures.length}`);
|
|
1111
|
-
}
|
|
1095
|
+
// Apply all client-side filters using centralized function
|
|
1096
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
1112
1097
|
|
|
1113
1098
|
const lastDoc = querySnapshot.docs.length > 0 ? querySnapshot.docs[querySnapshot.docs.length - 1] : null;
|
|
1114
1099
|
console.log(`[PROCEDURE_SERVICE] Strategy 4 success: ${procedures.length} procedures`);
|
|
@@ -1132,6 +1117,109 @@ export class ProcedureService extends BaseService {
|
|
|
1132
1117
|
}
|
|
1133
1118
|
}
|
|
1134
1119
|
|
|
1120
|
+
/**
|
|
1121
|
+
* Applies in-memory filters to procedures array
|
|
1122
|
+
* Used when Firestore queries fail or for complex filtering
|
|
1123
|
+
*/
|
|
1124
|
+
private applyInMemoryFilters(procedures: Procedure[], filters: any): (Procedure & { distance?: number })[] {
|
|
1125
|
+
let filteredProcedures = [...procedures]; // Create copy to avoid mutating original
|
|
1126
|
+
|
|
1127
|
+
// Name search filter
|
|
1128
|
+
if (filters.nameSearch && filters.nameSearch.trim()) {
|
|
1129
|
+
const searchTerm = filters.nameSearch.trim().toLowerCase();
|
|
1130
|
+
filteredProcedures = filteredProcedures.filter(procedure => {
|
|
1131
|
+
const name = (procedure.name || '').toLowerCase();
|
|
1132
|
+
const nameLower = procedure.nameLower || '';
|
|
1133
|
+
return name.includes(searchTerm) || nameLower.includes(searchTerm);
|
|
1134
|
+
});
|
|
1135
|
+
console.log(`[PROCEDURE_SERVICE] Applied name filter, results: ${filteredProcedures.length}`);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// Price filtering
|
|
1139
|
+
if (filters.minPrice !== undefined || filters.maxPrice !== undefined) {
|
|
1140
|
+
filteredProcedures = filteredProcedures.filter(procedure => {
|
|
1141
|
+
const price = procedure.price || 0;
|
|
1142
|
+
if (filters.minPrice !== undefined && price < filters.minPrice) return false;
|
|
1143
|
+
if (filters.maxPrice !== undefined && price > filters.maxPrice) return false;
|
|
1144
|
+
return true;
|
|
1145
|
+
});
|
|
1146
|
+
console.log(`[PROCEDURE_SERVICE] Applied price filter (${filters.minPrice}-${filters.maxPrice}), results: ${filteredProcedures.length}`);
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// Rating filtering
|
|
1150
|
+
if (filters.minRating !== undefined || filters.maxRating !== undefined) {
|
|
1151
|
+
filteredProcedures = filteredProcedures.filter(procedure => {
|
|
1152
|
+
const rating = procedure.reviewInfo?.averageRating || 0;
|
|
1153
|
+
if (filters.minRating !== undefined && rating < filters.minRating) return false;
|
|
1154
|
+
if (filters.maxRating !== undefined && rating > filters.maxRating) return false;
|
|
1155
|
+
return true;
|
|
1156
|
+
});
|
|
1157
|
+
console.log(`[PROCEDURE_SERVICE] Applied rating filter, results: ${filteredProcedures.length}`);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
// Treatment benefits filtering
|
|
1161
|
+
if (filters.treatmentBenefits && filters.treatmentBenefits.length > 0) {
|
|
1162
|
+
const benefitsToMatch = filters.treatmentBenefits;
|
|
1163
|
+
filteredProcedures = filteredProcedures.filter(procedure => {
|
|
1164
|
+
const procedureBenefits = procedure.treatmentBenefits || [];
|
|
1165
|
+
return benefitsToMatch.some((benefit: any) => procedureBenefits.includes(benefit));
|
|
1166
|
+
});
|
|
1167
|
+
console.log(`[PROCEDURE_SERVICE] Applied benefits filter, results: ${filteredProcedures.length}`);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// Procedure family filtering
|
|
1171
|
+
if (filters.procedureFamily) {
|
|
1172
|
+
filteredProcedures = filteredProcedures.filter(procedure => procedure.family === filters.procedureFamily);
|
|
1173
|
+
console.log(`[PROCEDURE_SERVICE] Applied family filter, results: ${filteredProcedures.length}`);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// Category filtering
|
|
1177
|
+
if (filters.procedureCategory) {
|
|
1178
|
+
filteredProcedures = filteredProcedures.filter(procedure => procedure.category?.id === filters.procedureCategory);
|
|
1179
|
+
console.log(`[PROCEDURE_SERVICE] Applied category filter, results: ${filteredProcedures.length}`);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// Subcategory filtering
|
|
1183
|
+
if (filters.procedureSubcategory) {
|
|
1184
|
+
filteredProcedures = filteredProcedures.filter(procedure => procedure.subcategory?.id === filters.procedureSubcategory);
|
|
1185
|
+
console.log(`[PROCEDURE_SERVICE] Applied subcategory filter, results: ${filteredProcedures.length}`);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// Technology filtering
|
|
1189
|
+
if (filters.procedureTechnology) {
|
|
1190
|
+
filteredProcedures = filteredProcedures.filter(procedure => procedure.technology?.id === filters.procedureTechnology);
|
|
1191
|
+
console.log(`[PROCEDURE_SERVICE] Applied technology filter, results: ${filteredProcedures.length}`);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
// Geo-radius filter
|
|
1195
|
+
if (filters.location && filters.radiusInKm && filters.radiusInKm > 0) {
|
|
1196
|
+
const location = filters.location;
|
|
1197
|
+
const radiusInKm = filters.radiusInKm;
|
|
1198
|
+
filteredProcedures = filteredProcedures.filter(procedure => {
|
|
1199
|
+
const clinicLocation = procedure.clinicInfo?.location;
|
|
1200
|
+
if (!clinicLocation?.latitude || !clinicLocation?.longitude) {
|
|
1201
|
+
return false;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
const distance = distanceBetween(
|
|
1205
|
+
[location.latitude, location.longitude],
|
|
1206
|
+
[clinicLocation.latitude, clinicLocation.longitude]
|
|
1207
|
+
) / 1000; // Convert to km
|
|
1208
|
+
|
|
1209
|
+
// Attach distance for frontend sorting/display
|
|
1210
|
+
(procedure as any).distance = distance;
|
|
1211
|
+
|
|
1212
|
+
return distance <= radiusInKm;
|
|
1213
|
+
});
|
|
1214
|
+
console.log(`[PROCEDURE_SERVICE] Applied geo filter, results: ${filteredProcedures.length}`);
|
|
1215
|
+
|
|
1216
|
+
// Sort by distance when geo filtering is applied
|
|
1217
|
+
filteredProcedures.sort((a, b) => ((a as any).distance || 0) - ((b as any).distance || 0));
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
return filteredProcedures as (Procedure & { distance?: number })[];
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1135
1223
|
private handleGeoQuery(filters: any): Promise<{ procedures: (Procedure & { distance?: number })[]; lastDoc: any }> {
|
|
1136
1224
|
console.log('[PROCEDURE_SERVICE] Executing geo query with enhanced debugging');
|
|
1137
1225
|
|
|
@@ -1160,29 +1248,8 @@ export class ProcedureService extends BaseService {
|
|
|
1160
1248
|
return getDocs(q).then(querySnapshot => {
|
|
1161
1249
|
let procedures = querySnapshot.docs.map(doc => ({ ...doc.data(), id: doc.id } as Procedure));
|
|
1162
1250
|
|
|
1163
|
-
// Apply geo filtering
|
|
1164
|
-
procedures =
|
|
1165
|
-
const clinicLocation = procedure.clinicInfo?.location;
|
|
1166
|
-
if (!clinicLocation?.latitude || !clinicLocation?.longitude) {
|
|
1167
|
-
return false;
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
const distance = distanceBetween(
|
|
1171
|
-
[location.latitude, location.longitude],
|
|
1172
|
-
[clinicLocation.latitude, clinicLocation.longitude]
|
|
1173
|
-
) / 1000; // Convert to km
|
|
1174
|
-
|
|
1175
|
-
// Add distance to procedure object
|
|
1176
|
-
(procedure as any).distance = distance;
|
|
1177
|
-
|
|
1178
|
-
return distance <= radiusInKm;
|
|
1179
|
-
});
|
|
1180
|
-
|
|
1181
|
-
// Sort by distance
|
|
1182
|
-
procedures.sort((a, b) => ((a as any).distance || 0) - ((b as any).distance || 0));
|
|
1183
|
-
|
|
1184
|
-
// Limit to pagination size
|
|
1185
|
-
procedures = procedures.slice(0, filters.pagination || 10);
|
|
1251
|
+
// Apply all filters using centralized function (includes geo filtering)
|
|
1252
|
+
procedures = this.applyInMemoryFilters(procedures, filters);
|
|
1186
1253
|
|
|
1187
1254
|
console.log(`[PROCEDURE_SERVICE] Geo query success: ${procedures.length} procedures within ${radiusInKm}km`);
|
|
1188
1255
|
|