@blackcode_sa/metaestetics-api 1.8.15 → 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.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +268 -90
- package/dist/index.mjs +268 -90
- package/package.json +1 -1
- package/src/services/clinic/utils/filter.utils.ts +103 -45
- package/src/services/practitioner/practitioner.service.ts +118 -33
- package/src/services/procedure/procedure.service.ts +111 -44
|
@@ -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
|
|